14.3. FreeBSD の安全性を高める

この節では、前節 でとりあげた FreeBSD システムの安全性を高める方法について説明します。

14.3.1. root アカウントの安全性を高める

ほとんどのシステムでは、 root アカウントに割り当てたパスワードが 1 つあります。 このパスワードはいつでも不正利用の危険に晒されていると考えてください。 これはパスワードを無効にすべきだと言っているのではありません。 パスワードは、マシンにコンソールからアクセスするのには、 ほとんどいつでも必要なものです。 しかしながら、コンソール以外からは、 そして可能なら su(1) コマンドを実行する場合もパスワードを使えないようにするべきです。 たとえば、/etc/ttys のエントリにおいて、 特定のターミナルに対し root でログインできないように insecure と設定してください。 FreeBSD では、デフォルトで、 /etc/ssh/sshd_config において PermitRootLoginno と設定されているので、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 チケットにタイムアウトを設定でき、 設定した期間が経過するとユーザに新しいパスワードを選ぶように要求するといった追加の制限を課することができます。

14.3.2. root 権限で実行されているサーバと SUID/SGID バイナリの安全性を高める

用心深いシステム管理者は、必要なサービスだけを有効にし、 サードパーティ製のサーバは、 よくバグを持っていがちだということに注意しているものです。 注意深くチェックしていないサーバは、決して実行してはいけません。 多くのデーモンは、サービス専用のアカウント、もしくは 砂場 (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 へ書き込みができます。 ユーザが端末プログラムやキーボードをシミュレーションする機能を持ったエミュレータを使っている場合、 侵入者は潜在的に、 結局そのユーザとして実行されるコマンドをユーザの端末にエコーさせるデータストリームを生成できる可能性があります。

14.3.3. ユーザアカウントの安全性を高める

ユーザアカウントは、普通、安全性を高めることが最も困難です。 気を配ってユーザアカウントを監視するよりほかありません。 ユーザアカウントに対し ssh(1) や Kerberos を利用するには、 システム管理がさらに増えたりテクニカルサポートが必要になりますが、 暗号化パスワードファイルと比較するとはるかに良い方法を提供します。

14.3.4. パスワードファイルの安全性を高める

できるだけ多くのパスワードをアスタリスクで外し、 それらのアカウントのアクセスには ssh(1) や Kerberos を使うようにすることが、唯一の確実な方法です。 暗号化パスワードファイル (/etc/spwd.db) は root でのみ読み出し可能だけれども、 たとえ、侵入者が root の書き込み権限は得られなくとも、 読み出しアクセス権限を得ることは可能かもしれません。

ファイルの完全性のチェック 節で説明されているように、 セキュリティスクリプトでパスワードファイルの変更をチェックし、 報告するようにすべきです。

14.3.5. カーネルのコア、raw デバイス、 ファイルシステムの安全性を高める

最近のカーネルは、組み込みのパケット覗き見デバイス (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_enableYES とし、 kern_securelevel に必要とする値を設定することで、 システム起動時にセキュアレベルを高めることができます。

セキュリティレベルを 1 以上に設定すると、 追加専用および変更不可ファイルのフラグを外すことはできなくなり、 また raw デバイスへのアクセスが拒否されます。 より高いレベルに設定すると、より多くの操作に制限がかかります。 各セキュリティレベルの完全な説明については、 security(7) および init(8) をご覧ください。

注記:

セキュリティレベルを 1 以上に設定した場合には、 /dev/io へのアクセスがブロックされるため、 Xorg や、 installworld のプロセスでは、 いくつかのファイルの追加専用および変更不可のフラグは一時的にリセットされるため、 ソースから FreeBSD を構築してインストールするときなどで問題が引き起こされる可能性があります。 Xorg の問題については、 起動プロセス初期のセキュアレベルが十分低いときに xdm(1) を起動することで、この問題に対応できます。 このような応急処置は、 すべてのセキュリティレベルやそれらが課す潜在的なすべての制限には対応できないでしょう。 少し先を見越した計画的な対応をすべきです。 各セキュリティレベルで課される制限は、 システムを使用することによる利便性を著しく減らしてしまうため、 この制限を理解することは重要です。 また、各セキュリティレベルの制限を理解することで、 デフォルトの設定をよりシンプルにでき、 設定に関する意外性を少なくできるでしょう。

カーネルのセキュリティレベルを 1 以上に設定した場合には、 システム起動に関わる重要なバイナリやディレクトリ、 スクリプトファイル、そして、 セキュリティレベルが設定されるまでの間に実行されるすべてのものに対して、 schg フラグを設定することは有用でしょう。 システムをより高いセキュリティレベルで実行させるようにするが、 schg フラグを設定しないというところで妥協するという手もあります。 もう一つの可能性としては、単純に / および /usr を読み込み専用でマウントすることです。 ここで特筆すべきことは、システムを守ろうとして厳しくしすぎると、 侵入を検出することができなくなってしまうということです。

14.3.6. ファイルの完全性のチェック

システム管理者にできることは、 便利さという要素がその醜い頭を上げない程度に、 コアシステムの設定と制御ファイルを防御することだけです。 たとえば、/ および /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 つの方法は、 システムコンソールをシリアルポートにつないで走らせ、 コンソールを監視している安全なマシンに情報を集めることです。

14.3.7. 偏執狂的方法

多少偏執狂的になっても決して悪いことにはなりません。 原則的に、システム管理者は、 便利さに影響を与えない範囲でいくつでもセキュリティ機能を追加することができます。 また、いくらか考慮した結果、 便利さに影響を与えるセキュリティ機能を追加することもできます。 より重要なことは、 セキュリティ管理者はこれを多少混ぜこぜにして使うべきだということです。 もしこの章で書かれている推奨される方法をそのまま使用した場合は、 予想される攻撃者はやはりこの文書を読んでいるわけですから、 防御策を教えてしまうことになります。

14.3.8. サービス妨害攻撃

DoS 攻撃は、普通は、パケット攻撃です。 ネットワークを飽和させる最先端の偽造パケット (spoofed packet) 攻撃に対してシステム管理者が打てる手はそれほど多くありませんが、 一般的に、以下のような方法により、 その種の攻撃によってサーバがダウンしないことを確実にすることで、 被害をある限度に食い止めることはできます。

  1. サーバの fork の制限。

  2. ICMP 応答攻撃、ping broadcast などの踏み台攻撃の制限。

  3. カーネルの経路情報のキャッシュを過剰に用意する。

よくある 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, rtmaxcachesysctl(8) パラメータを参照して下さい。 でたらめな送信元 IP アドレスを用いた偽造パケット攻撃により、 カーネルは、一時的なキャッシュ経路を経路情報テーブルに生成します。 これは netstat -rna | fgrep W3 で見ることができます。 これらの経路は、普通は 1600 秒程度でタイムアウトになります。 カーネルがキャッシュ経路テーブルが大きくなり過ぎたことを検知すると、 カーネルは動的に rtexpire を減らしますが、rtminexpire より小さくなるようには決して減らしません。 これにより 2 つの問題が引き起こされます。

  1. 負荷の軽いサーバが突然攻撃された場合、 カーネルが十分素早く反応できないこと。

  2. カーネルが持続的攻撃に耐えられるほど十分 rtminexpire が低く設定されていないこと。

サーバが T3 もしくはそれより高速の回線でインターネットに接続されている場合、 sysctl(8) を用いて rtexpirertminexpire を手動で上書きしておくことが思慮深いことといえます。 ただし、どちらか一方でも 0 には決してしないで下さい。 コンピュータをクラッシュさせてしまうことになります。 両パラメータを 2 秒に設定すれば、 攻撃から経路情報テーブルを守るには十分でしょう。

14.3.9. Kerberos および ssh(1) を用いたアクセスの問題

もし、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_keysfrom=IP/DOMAIN を使用して、 特定のマシンからログインしてきたときのみ鍵が有効であるようにすることも勧めます。

本文書、および他の文書は https://download.freebsd.org/ftp/doc/ からダウンロードできます。

FreeBSD に関する質問がある場合には、 ドキュメント を読んだ上で <questions@FreeBSD.org> まで (英語で) 連絡してください。

本文書に関する質問については、 <doc@FreeBSD.org> まで電子メールを (英語で) 送ってください。