この節では、前節 でとりあげた FreeBSD システムの安全性を高める方法について説明します。
ほとんどのシステムでは、
root
アカウントに割り当てたパスワードが 1 つあります。
このパスワードはいつでも不正利用の危険に晒されていると考えてください。
これはパスワードを無効にすべきだと言っているのではありません。
パスワードは、マシンにコンソールからアクセスするのには、
ほとんどいつでも必要なものです。
しかしながら、コンソール以外からは、
そして可能なら su(1)
コマンドを実行する場合もパスワードを使えないようにするべきです。
たとえば、/etc/ttys
のエントリにおいて、
特定のターミナルに対し
root
でログインできないように
insecure
と設定してください。
FreeBSD では、デフォルトで、
/etc/ssh/sshd_config
において
PermitRootLogin
が no
と設定されているので、ssh(1) を使った
root
へログインは無効になっています。
すべてのアクセス手段、たとえば FTP
ようなサービスは、良くクラックの対象となることを理解してください。
root
への直接ログインは、
システムコンソール経由でのみ可能であるべきなのです。
システム管理者は
root
になれるようにしておく必要があるので、
追加のパスワード認証の設定が必要となります。
ひとつは、適切なユーザアカウントを
/etc/group
中の
wheel
に加える方法です。
wheel
のメンバは、su(1) を使って
root
になることが許されます。
実際に
root
アクセスの必要なユーザのみ
wheel
に置くようにすべきです。
Kerberos を使用して認証行う場合には、
root
のホームディレクトリに .k5login
を作成することで、
誰も wheel
に置く必要なく
ksu(1) することを許可できます。
アカウントを完全にロックするには、 pw(8) を使ってください。
#
pw lock staff
これにより、指定されたユーザは、ssh(1) を含むいかなる方法でもログインできなくなります。
アカウントへのアクセスをブロックするもう一つの方法は、
暗号化されたパスワードを
「*
」 1 文字に置き換えることです。
この文字は、暗号化されたパスワードにマッチすることはないので、
ユーザアクセスをブロックします。
たとえば、次のアカウントのエントリを、
foobar:R9DT/Fa1/LV9U:1000:1000::0:0:Foo Bar:/home/foobar:/usr/local/bin/tcsh
vipw(8) を使って以下のように変更します。
foobar:*:1000:1000::0:0:Foo Bar:/home/foobar:/usr/local/bin/tcsh
この変更によって
foobar
は、
通常のログインはできなくなります。
このようなアクセス制限をした後は、
サイトで Kerberos をセットアップしたり、
ユーザが ssh(1)
の鍵を設定するなどといった認証手段を利用しなければなりません。
これらのセキュリティの仕組みでは、 制限の強いサーバから制限の弱いサーバへログインすることを前提としています。 たとえば、サーバがネットワークサービスを実行させている場合、 ワークステーションではそれらのサービスを実行させてはなりません。 ワークステーションを十分に安全にしておくためには、 実行するサービスをゼロにするか、可能な限り減らし、 パスワードで保護されたスクリーンセーバを走らせておくべきです。 システムへの物理的アクセスが与えられたとすると、 もちろん言うまでもなく、 攻撃者はいかなる種類のセキュリティをもうち破ることができるのです。 幸いにも、システム破りの大多数は、ネットワーク経由でリモートから、 システムへの物理的アクセス手段を持たない人々によって行われています。
Kerberos を使うことで、 ユーザのパスワードの変更もしくは停止を一箇所で行なうことと、 ユーザがアカウントを持つすべてのマシンに即時にその効果を及ぼすことが可能となります。 アカウントが危険に晒されたときに、 すべてのマシン上の関連するパスワードを即座に変更する能力を過小評価してはいけません。 Kerberos では、Kerberos チケットにタイムアウトを設定でき、 設定した期間が経過するとユーザに新しいパスワードを選ぶように要求するといった追加の制限を課することができます。
用心深いシステム管理者は、必要なサービスだけを有効にし、
サードパーティ製のサーバは、
よくバグを持っていがちだということに注意しているものです。
注意深くチェックしていないサーバは、決して実行してはいけません。
多くのデーモンは、サービス専用のアカウント、もしくは
砂場 (sandbox) で起動させることができるので、
root
権限でサービスを実行する前には、よく考えてください。
telnetd(8) または rlogind(8)
のような安全ではないサービスは有効にしないでください。
他のシステムの潜在的なセキュリティホールには、
SUID-root および SGID バイナリがあります。
これらのバイナリは、
rlogin(1) のように、/bin
,
/sbin
, /usr/bin
または /usr/sbin
に存在するものがほとんどです。
100% 安全なものは存在しないとはいえ、
システムデフォルトの SUID/SGID バイナリは比較的安全といえます。
SUID バイナリは、
スタッフのみがアクセス可能な特別なグループに制限し、
使わない SUID バイナリは削除することが推奨されます。
SGID バイナリもほとんど同様の危険な存在になり得ます。
侵入者が kmem に SGID されたバイナリを破ることができた場合、
その侵入者は /dev/kmem
を読み出すことができるようになるでしょう。つまり、
暗号化されたパスワードファイルを読み出すことができるようになるので、
ユーザアカウントを、潜在的な危険に晒すことになります。他にも、
kmem
グループを破った侵入者が pty
を通して送られたキーストロークを監視できるという危険があります。
キーストロークには、安全な方法でログインするユーザが使っている pty
も含まれます。
tty
グループを破った侵入者は、ほぼ任意のユーザの
tty へ書き込みができます。
ユーザが端末プログラムやキーボードをシミュレーションする機能を持ったエミュレータを使っている場合、
侵入者は潜在的に、
結局そのユーザとして実行されるコマンドをユーザの端末にエコーさせるデータストリームを生成できる可能性があります。
ユーザアカウントは、普通、安全性を高めることが最も困難です。 気を配ってユーザアカウントを監視するよりほかありません。 ユーザアカウントに対し ssh(1) や Kerberos を利用するには、 システム管理がさらに増えたりテクニカルサポートが必要になりますが、 暗号化パスワードファイルと比較するとはるかに良い方法を提供します。
できるだけ多くのパスワードをアスタリスクで外し、
それらのアカウントのアクセスには
ssh(1) や Kerberos を使うようにすることが、唯一の確実な方法です。
暗号化パスワードファイル
(/etc/spwd.db
) は
root
でのみ読み出し可能だけれども、
たとえ、侵入者が root の書き込み権限は得られなくとも、
読み出しアクセス権限を得ることは可能かもしれません。
ファイルの完全性のチェック 節で説明されているように、 セキュリティスクリプトでパスワードファイルの変更をチェックし、 報告するようにすべきです。
最近のカーネルは、組み込みのパケット覗き見デバイス
(packet sniffing device) ドライバを備えているものがほとんどです。
FreeBSD では bpf
と呼ばれています。
このデバイスは DHCP で必要となるため、
DHCP を提供したり使う必要のないシステムでは、
カスタムカーネルコンフィグレーションファイルから外すことができます。
bpf
を外しても、
/dev/mem
および
/dev/kmem
という問題がまだ残っています。
侵入者は raw ディスクデバイスに書き込むこともできます。
やる気まんまんの侵入者は、kldload(8)
を使って自分独自の bpf
、
もしくは他の覗き見デバイスを動作中のカーネルにインストールできます。
この問題を避けるため、カーネルをより高いセキュリティレベル、
少なくともセキュリティレベル 1 で実行させる必要があります。
カーネルのセキュリティレベルはいくつかの方法で設定できます。
現在動いているカーネルのセキュリティレベルを高める最も簡単な方法は、
kern.securelevel
を設定する方法です。
#
sysctl kern.securelevel=1
デフォルトでは、FreeBSD のカーネルはセキュリティレベル
-1 で起動します。
このセキュリティレベルは、
変更不可のファイルフラグを外したり、
すべてのデバイスに対して読み込みおよび書き込みができたりするので、
「insecure mode」 と呼ばれます。
このセキュアレベルは、管理者または init(8)
による起動時のスクリプトにより変更されない限り -1 のままです。
/etc/rc.conf
において、
kern_securelevel_enable
を
YES
とし、
kern_securelevel
に必要とする値を設定することで、
システム起動時にセキュアレベルを高めることができます。
セキュリティレベルを 1 以上に設定すると、 追加専用および変更不可ファイルのフラグを外すことはできなくなり、 また raw デバイスへのアクセスが拒否されます。 より高いレベルに設定すると、より多くの操作に制限がかかります。 各セキュリティレベルの完全な説明については、 security(7) および init(8) をご覧ください。
セキュリティレベルを 1 以上に設定した場合には、
/dev/io
へのアクセスがブロックされるため、
Xorg や、
installworld
のプロセスでは、
いくつかのファイルの追加専用および変更不可のフラグは一時的にリセットされるため、
ソースから FreeBSD
を構築してインストールするときなどで問題が引き起こされる可能性があります。
Xorg の問題については、
起動プロセス初期のセキュアレベルが十分低いときに
xdm(1) を起動することで、この問題に対応できます。
このような応急処置は、
すべてのセキュリティレベルやそれらが課す潜在的なすべての制限には対応できないでしょう。
少し先を見越した計画的な対応をすべきです。
各セキュリティレベルで課される制限は、
システムを使用することによる利便性を著しく減らしてしまうため、
この制限を理解することは重要です。
また、各セキュリティレベルの制限を理解することで、
デフォルトの設定をよりシンプルにでき、
設定に関する意外性を少なくできるでしょう。
カーネルのセキュリティレベルを 1 以上に設定した場合には、
システム起動に関わる重要なバイナリやディレクトリ、
スクリプトファイル、そして、
セキュリティレベルが設定されるまでの間に実行されるすべてのものに対して、
schg
フラグを設定することは有用でしょう。
システムをより高いセキュリティレベルで実行させるようにするが、
schg
フラグを設定しないというところで妥協するという手もあります。
もう一つの可能性としては、単純に
/
および /usr
を読み込み専用でマウントすることです。
ここで特筆すべきことは、システムを守ろうとして厳しくしすぎると、
侵入を検出することができなくなってしまうということです。
システム管理者にできることは、
便利さという要素がその醜い頭を上げない程度に、
コアシステムの設定と制御ファイルを防御することだけです。
たとえば、/
および
/usr
にある大部分のファイルに schg
ビットを設定するために chflags(1)
を使用するのは、おそらく逆効果でしょう。
なぜなら、そうすることでファイルは保護できますが、
侵入を検出する窓を閉ざしてしまうことにもなるからです。
セキュリティ対策は、
侵入の可能性を検出できなければ、有用ではなく、
もっと悪ければ、安全性に対する間違った感覚を植え付けてしまいます。
セキュリティに対する仕事の半分は、
攻撃者を攻撃の最中に捕えるようにするために、
攻撃者を食い止めるのではなく侵入を遅らせることなのです。
侵入を検出する最も良い方法は、変更されていたり、 消えていたり、入れた覚えがないのに入っているファイルを探すことです。 変更されたファイルを探すのに最も良い方法は、もう一つの しばしば中央に集められた、 アクセスが制限されたシステムから行なうものです。 さらに安全でアクセス制限されたシステム上でセキュリティ用スクリプトを書けば、 スクリプトは潜在的な攻撃者からはほぼ見えなくなります。 この有効性を最大限に活用するためには、 アクセスの制限されたマシンから他のマシンへのかなりのアクセスを許可する必要があります。 普通は、読み込み専用の NFS エクスポートをしたり、 ssh(1) 鍵のペアを設定したりします。 ネットワークのトラフィックを別にして、 NFS は最も可視性のない方法です。 管理者は、各クライアント上のファイルシステムを、 事実上検出されずに監視できるようになります。 アクセス制限されたサーバがスイッチを通してクライアントに接続されている場合、 たいてい NFS がより良い選択肢です。 アクセス制限されたサーバが、 いくつかのルーティング層を通してクライアントに接続している場合、 NFS はあまりにも危険なので、 ssh(1) の方が良い方法でしょう。
アクセス制限されたマシンに、
監視しようとするクライアントシステムへの少なくとも読み込みのアクセス権を与えたら、
次に監視するためのスクリプトを書かなくてはいけません。
NFS マウントをすれば、find(1) や md5(1)
などの単純なシステムユーティリティでスクリプトを書くことができます。
少なくとも 1 日 1 回、クライアントのシステムファイルを直接
md5(1) にかけ、
さらにもっと頻繁に /etc
および
/usr/local/etc
にあるようなコントロール用ファイルを試験するのが一番です。
アクセス制限されたマシンが正しいと知っている、
基となる md5 情報と比べて違いが見つかった場合、
システム管理者に警告するようにすべきです。
優れたセキュリティ用スクリプトは、
/
および /usr
などのシステムパーティション上で不適当に
SUID されたバイナリや、
新たに作成されたファイルや削除されたファイルがないかどうかを調べるでしょう。
NFS ではなく、ssh(1) を使用する場合は、 セキュリティ用スクリプトを書くのはより難しいことです。 たとえば、スクリプトを動かすためには、クライアントに対してスクリプトを scp(1) しなくてはいけませんし、 クライアントマシンの ssh(1) クライアントはすでに攻撃されてしまっているかもしれません。 安全でないリンク上の場合は ssh(1) は必要かもしれませんが、 扱いはとても大変になります。
優れたセキュリティ用スクリプトは、
.rhosts
,
.ssh/authorized_keys
などの隠し設定ファイルの変更もチェックするものです。
これらは MD5
チェックの範囲外になってしまうであろうファイル群です。
ユーザ用のディスク容量が非常に大きい場合は、
パーティション上の各ファイルを見て回るのに大変な時間がかかるかもしれません。
この場合は、mount(8) により nosuid
を使うことで、マウントフラグを設定して、
SUID されたバイナリを置けないようにするのが良い考えです。
少なくとも週に 1 度はファイルシステムをスキャンするべきです。
なぜなら、目的は、侵入が成功したかどうかに関わらず、
不正侵入の試みがあったことの検出をすることだからです。
プロセスアカウンティング (accton(8) 参照) は、 マシンへの侵入を検出するためのメカニズムとして推奨できる、 比較的オーバヘッドの少ない FreeBSD の機能です。 侵入を受けた後でも当該ファイルが無傷である場合に、 侵入者がどのようにしてシステムに侵入したかを追跡するのに特に役立ちます。
最後に、 セキュリティスクリプトはログファイルを処理するようにし、 ログファイル自体もできるだけ安全性の高い方法で生成するようにし、 リモートの syslog サーバに送信するようにすべきです。 侵入者は自分の侵入の痕跡を覆い隠そうとしますし、また、 ログファイルはシステム管理者が最初の侵入の時刻と方法を追跡してゆくために極めて重要です。 ログファイルを永久に残しておくための 1 つの方法は、 システムコンソールをシリアルポートにつないで走らせ、 コンソールを監視している安全なマシンに情報を集めることです。
多少偏執狂的になっても決して悪いことにはなりません。 原則的に、システム管理者は、 便利さに影響を与えない範囲でいくつでもセキュリティ機能を追加することができます。 また、いくらか考慮した結果、 便利さに影響を与えるセキュリティ機能を追加することもできます。 より重要なことは、 セキュリティ管理者はこれを多少混ぜこぜにして使うべきだということです。 もしこの章で書かれている推奨される方法をそのまま使用した場合は、 予想される攻撃者はやはりこの文書を読んでいるわけですから、 防御策を教えてしまうことになります。
DoS 攻撃は、普通は、パケット攻撃です。 ネットワークを飽和させる最先端の偽造パケット (spoofed packet) 攻撃に対してシステム管理者が打てる手はそれほど多くありませんが、 一般的に、以下のような方法により、 その種の攻撃によってサーバがダウンしないことを確実にすることで、 被害をある限度に食い止めることはできます。
サーバの fork の制限。
ICMP 応答攻撃、ping broadcast などの踏み台攻撃の制限。
カーネルの経路情報のキャッシュを過剰に用意する。
よくある DoS 攻撃は、fork
するサーバに対して攻撃するもので、
多くの子プロセスを起動させることにより、
メモリ、ファイル記述子などを使いつくし、
ホストシステムを最終的に停止させます。
inetd(8) には、
この種の攻撃を制限するオプションがいくつかあります。
マシンがダウンすることを防止することは可能ですが、
この種の攻撃によりサービスが中断することを防止することは一般的に言ってできないことに注意する必要があります。
inetd(8) を注意深く読んで下さい。特に、
-c
, -C
, -R
に注意して下さい。IP 偽造攻撃 (spoofed-IP attack) は
inetd(8) の -C
の裏をかけるので、
一般にオプションを組み合わせて使用すべきです。
スタンドアロンサーバの中には、自分自身で fork
を制限するパラメータを持っているものがあります。
Sendmail には、
-OMaxDaemonChildren
があります。
システム負荷の値変化には遅れがあるので、
Sendmail
の負荷限界指定オプションを使うよりも、
このオプションを使う方がまともに動作する可能性ははるかに高いです。
Sendmail を開始する際は、
通常見込まれる負荷を扱える程度に十分高いが、
コンピュータが操作できない数の Sendmail
インスタンスの値よりは低い値に
MaxDaemonChildren
を設定してください。
Sendmail を
-ODeliveryMode=queued
を使って、
キュー処理モードで実行したり、
デーモン (sendmail -bd
)
をキュー処理用プロセス (sendmail -q15m
)
と別に実行することも、用心深いことと言えます。
リアルタイムでの配送を望むのであれば、
-q1m
のようにすることで、
キュー処理をはるかに短い時間間隔で行うことができます。
いずれにしても、MaxDaemonChildren
に合理的な値を確実に指定して、
なだれをうって失敗することがないようにして下さい。
syslogd(8)
は直接攻撃される可能性があるので、可能ならばいつでも
-s
を用いることを強く推奨します。
これができないなら、
-a
を使って下さい。
逆 identd などの接続返し (connect-back) を行うサービスについては直接攻撃を受ける可能性があるので、 十分注意を払うようにするべきです。 こういう事情があるので、TCP wrapper の逆 ident 機能を使うことは推奨されません。
境界ルータのところでファイアウォールを設けて、
外部からのアクセスに対して内部サービスを防御することは推奨されます。
これは、LAN の外部からの飽和攻撃を防ぐことにあり、
内部サービスをネットワークベースの root
権限への攻撃から防御することにはあまり考慮を払っていません。
ファイアウォールは、デフォルトではすべての通信を禁止し、
許可する通信のみを明示して設定するように、常に排他的に設定して下さい。
FreeBSD では、net.inet.ip.portrange
sysctl(8) 変数により、
動的バインドに使用されるポート番号の範囲を制御できます。
また別のよくある DoS 攻撃として、
踏み台攻撃と呼ばれるものがあります。これは、
あるサーバを攻撃し、その結果として生成される応答がサーバ自身、
ローカルネットワーク、
もしくは他のマシンを過負荷に追い込むようにする攻撃です。
この種の攻撃の中で最もありふれたものに、
ICMP ping broadcast 攻撃があります。
攻撃者は、攻撃するマシンのアドレスを送信元アドレスに設定した
ping パケットを偽造して、対象の LAN
のブロードキャストアドレスに向けてパケットを送信します。
境界にあるルータがブロードキャストアドレスに対する
ping パケットをドロップするように設定されていない場合、LAN は、
詐称された送信元アドレスに向けて、
犠牲となるマシンが飽和するまで応答パケットを生成します。
異なるネットワーク上のいくつものブロードキャストアドレスに対して同時に攻撃する場合には、
とくにひどいことになります。
2 番目の踏み台攻撃は、
サーバの受信ネットワークを飽和させるような
ICMP エラー応答を生成するパケットを生成し、
その結果としてサーバが送信ネットワークを ICMP
応答で飽和させてしまう攻撃です。
メモリを消費し尽くさせることにより、
この種の攻撃でサーバをクラッシュさせることが可能です。
サーバが生成した ICMP 応答を十分速く送信できない場合、
とくにひどいことになります。
この種の攻撃の効果を抑制するには、
sysctl(8) 変数の net.inet.icmp.icmplim
を使ってください。
踏み台攻撃の 3 つめの主要なクラスに属する攻撃は、
UDP echo サービスのような、特定の inetd(8)
内部サービスに関連するものです。
攻撃者は、送信元アドレスがサーバ A の echo
ポートであり、送信先アドレスがサーバ B の echo
ポートであるように UDP パケットを偽造します。
ここでサーバ A, B はともに同じ
LAN に接続されています。この 2 つのサーバは、
この一つのパケットを両者の間で互いに相手に対して打ち返しあいます。
攻撃者は、このようなパケットをほんのいくつか注入するだけで、
両方のサーバと LAN を過負荷状態にすることができます。
同様の問題が chargen
ポートにも存在します。
この手の inetd 内部テストサービスは無効にしてください。
偽造パケット攻撃は、
カーネルの経路情報キャッシュに過負荷を生じさせるために用いられることもあります。
net.inet.ip.rtexpire
,
rtminexpire
,
rtmaxcache
の sysctl(8) パラメータを参照して下さい。
でたらめな送信元 IP アドレスを用いた偽造パケット攻撃により、
カーネルは、一時的なキャッシュ経路を経路情報テーブルに生成します。
これは netstat -rna | fgrep W3
で見ることができます。
これらの経路は、普通は 1600 秒程度でタイムアウトになります。
カーネルがキャッシュ経路テーブルが大きくなり過ぎたことを検知すると、
カーネルは動的に rtexpire
を減らしますが、rtminexpire
より小さくなるようには決して減らしません。
これにより 2 つの問題が引き起こされます。
負荷の軽いサーバが突然攻撃された場合、 カーネルが十分素早く反応できないこと。
カーネルが持続的攻撃に耐えられるほど十分
rtminexpire
が低く設定されていないこと。
サーバが T3
もしくはそれより高速の回線でインターネットに接続されている場合、
sysctl(8) を用いて
rtexpire
と rtminexpire
を手動で上書きしておくことが思慮深いことといえます。
ただし、どちらか一方でも 0 には決してしないで下さい。
コンピュータをクラッシュさせてしまうことになります。
両パラメータを 2 秒に設定すれば、
攻撃から経路情報テーブルを守るには十分でしょう。
もし、Kerberos と ssh(1) を使いたいのだとしたら、
両者に関して言っておかねばならない問題がいくつかあります。
Kerberos は大変優れた認証プロトコルですが、Kerberos 化された
telnet(1) および rlogin(1) には、
バイナリストリームを扱うのに不向きになってしまうようなバグがあります。
デフォルトでは、Kerberos は -x
を使わない限りセッションを暗号化してくれません。
一方 ssh(1) では、
デフォルトですべてを暗号化してくれます。
ssh(1) はとても良く働いてくれますが、
デフォルトで暗号鍵を転送してしまいます。
これは、安全なワークステーションから、
安全でないマシンへのアクセスに
ssh(1) を使っているユーザにセキュリティリスクを引き起こします。
鍵そのものが見えてしまうわけではありませんが、
ssh(1) は login している間、転送用ポートを作ります。
攻撃者が安全でないマシンの
root
を破ったら、
このポートを使って、
この暗号鍵でロックが外れる他のマシンへのアクセスを得てしまいます。
可能な時はいつでも、スタッフのログインには Kerberos を組み合せた
ssh(1) を使用することを勧めます。
ssh(1) は、Kerberos 対応機能と一緒にコンパイルできます。
こうすると、見えてしまうかもしれない
SSH 鍵をあまりあてにしないで良いようになり、
一方で、Kerberos 経由でパスワードが保護されます。
鍵は、安全なマシンからの自動化されたタスクのみに使用するべきです。
Kerberos はこの用途には不向きです。
また、SSH の設定で鍵転送をしないようにするか、
あるいは authorized_keys
の from=IP/DOMAIN
を使用して、
特定のマシンからログインしてきたときのみ鍵が有効であるようにすることも勧めます。
本文書、および他の文書は https://download.freebsd.org/ftp/doc/ からダウンロードできます。
FreeBSD に関する質問がある場合には、
ドキュメント を読んだ上で
<questions@FreeBSD.org> まで (英語で) 連絡してください。
本文書に関する質問については、
<doc@FreeBSD.org> まで電子メールを (英語で) 送ってください。