IBM®
本文へジャンプ
    Japan [変更]    ご利用条件
 
 
検索範囲検索:    
    ホーム    製品    サービス & ソリューション    サポート & ダウンロード    マイアカウント    
skip to main content

developerWorks Japan  >  Linux  >

セキュアなプログラマー: 特権を最小限にとどめる

バグの毒牙を抜く

developerWorks
ページオプション

JavaScript を要するドキュメントオプションは表示されません

原文はこちら

原文はこちら


レベル: 中級

David Wheeler (dwheelerNOSPAM@dwheeler.com), Research staff member, Institute for Defense Analyses

2004年 5月 20日

セキュアなプログラムでは、バグがセキュリティ脆弱性の元にならないように特権を最小限にとどめる必要があります。この記事では特権の制限のために特権モジュールや許可される特権を最小化する方法、また特権が有効となっている時間を最小限にとどめる方法について説明します。ここでは伝統的なUNIXライクな特権関連の機構にとどまらず、FreeBSDjail()や、Linux Security Modules (LSM)フレームワーク、それにSecurity-Enhanced Linux (SELinux)といった新しい機構についても説明します。

2003年3月3日、Internet Security SystemsはSendmailに深刻な脆弱性があると警告しました。電子メールは全てメール転送エージェント(mail transfer agent: MTA)を使って転送されますが、Sendmailは最も一般的なMTAなので、この警告は世界中の組織に影響を与えました。攻撃者が「from」「to」「cc」等のフィールドをうまく作れば、Sendmailを通常の設定で実行しているどんなマシンに対しても、送信者となった攻撃者が完全な(rootとしての)制御を奪えるという問題があったのです。さらに悪いことに、典型的なファイアーウォールでは、ファイアーウォール内部にあるマシンをこの攻撃から保護することはできないのです。

この脆弱性の直接原因はSendmailのセキュリティ・チェックの一つに欠陥があり、バッファーフローを許してしまうというものでした。ただそこに至る大きな要因として、Sendmailは多くの場合一体の「setuid root」プログラムとしてインストールされ、その下で実行しているシステムに完全な制御が渡ってしまうという問題があったのです。ですから攻撃者はSendmailにあるどんな欠陥でも利用して、即座にシステム全体の制御を奪うことができてしまうのです。

この設計は必要なものなのでしょうか。そんなことはありません。Sendmailに対抗するMTAとして一般的なものにWietse VenemaのPostfixがあります。PostfixもSendmailと同様いくつかのセキュリティ・チェックを行うのですが、Postfixは特権を最小限にとどめる一連のモジュールとして作られているのです。そのため一般的にPostfixは、Sendmailよりもセキュアなプログラムとして受け入れられています。この記事では特権を最小にとどめる方法についての説明なので、皆さんのプログラムにも同じ考え方を応用することができます。

特権を最小にとどめるための基本

現実世界のプログラムにはバグがあるものです。欲しいと思って作るものではありませんが、実際にできてしまうものです。複雑な要求やスケジュールの圧力、環境の変化などがあるため、バグのないプログラムは現実的にはあり得ません。それまでは高度な数学的手法を駆使して正しいと証明されたプログラムであっても、バグを含み得るのです。なぜでしょうか。理由の一つとして、証明のためには多くの仮定がなされており、通常はそうした仮定の一部が完全には正しくないことが挙げられます。大部分のプログラムは様々理由からそれほど厳密にはチェックされません。また例え現在は全くバグが無い(あり得ないですが)としても、メンテナンスのための変更や環境の変更などによって、後からバグが発生する可能性があります。ですから現実世界に対応するためには、中にバグがあってもセキュアなプログラムを開発する必要があるのです。

バグがあってもプログラムをセキュアにするために重要なのは、特権を最小にすることです。特権というのは単純に、誰にでも許されているわけではない何かをするための許可です。UNIXライクのシステムでは「root」ユーザー特権、別ユーザー特権、グループのメンバーとしての特権などが、特権として最も一般的なものでしょう。一部のシステムでは、特定なファイルを読み書きするための特権があります。いずれにせよ、特権を最小限にとどめるには次のようなことが必要です。

  • 特権を必要とするプログラム部分にのみ特権を与える
  • その部分で絶対に必要とされる、特定な特権のみを許可する
  • こうした特権が有効となる時間を制限する、または絶対最低限の期間中のみ有効にする

これらは目標であって絶対的なものではありません。インフラ(オペレーティング・システムや仮想マシン)によってはこれを正確に実行するのは難しいかも知れませんし、正確に実行するための作業が複雑すぎて、さらに多くのバグを招くことになってしまうかも知れません。それでも、こうした目標に近づけば近づくだけ、バグでセキュリティ問題を引き起こす可能性は低くなります。また、たとえバグがセキュリティ問題を引き起こしたとしても、問題の程度は軽くて済むはずです。さらに、特別な権限を持つプログラム部分はごく一部のみだと自信を持って言えるのであれば、その部分のみを攻撃から守るように、さらに時間をかけることができるのです。この考え方は新しいものではありません。セキュリティの原則を述べたSaltzerとSchroederによる1975年発表の素晴らしい論文では、特に特権制限の原則を取り上げています(参考文献)。特権の制限のような考え方は時代を超えたものです。

次の3セクションではこうした目標について、UNIXライクなシステムでの実装方法を含めて順に説明して行きます。その後で、FreeBSDやLinuxで利用可能な機構について、NSAのSecurity-Enhanced Linux (SELinux)を含めて説明します。




上に戻る


特権モジュールを最小にとどめる

先に書いたように、特権が必要なプログラム部分のみが特権を持つべきです。これはつまり、プログラムを設計する時にはいくつかの別々な部分に分割し、特権が必要なのは小さな独立部分のみ、となるようにすることです。

もし別々の部分が並行に実行する必要がある場合には、UNIXライクのシステムでは(スレッドではなく)プロセスを使います。スレッドはセキュリティ特権を共有するため、動作がおかしいスレッドがあると、そのプロセス中の他のスレッド全てが妨害されてしまいます。そのプログラム特権部分以外の部分が、まるでその特権部分を攻撃しているかのような想定で特権部分を書くべきなのです。実際、ある日そういう攻撃があるかも知れないのです! 特権部分は最小限のこと以外はしないようにします。機能が限定されているということは、悪用の余地も限定されるのです。

一般的な手法としては、ごく機能が限定され、(setuidやsetgidなどのような)特別な権限を持ったコマンドライン・ツールを作ることです。UNIXのpasswdコマンドがその一例です。これはパスワードを変更する(setuid root)という特別な権限を持ったコマンドライン・ツールですが、これでできるのはパスワードの変更のみです。そうすると各種のGUIツールがpasswdに対して実際に変更を行うように要求するのです。setuidやsetgidプログラムでは全ての入力を確実に保護するのが非常に困難なため、可能な限り避けるべきです。そうは言ってもsetuid/setgidプログラムを作る必要のある時もありますが、その時でもプログラムはできるだけ小さく、また限定されたものにすべきです。

他にも手法はあります。例えば特別な権限を持った小さな「サーバー」プロセスを使うという手段があります。このサーバーはある特定なリクエストしか許可せず、しかも許可されたものからのリクエストである、ということを確認した後でないとリクエストを許可しないのです。その他一般によく使われる手法としては、まず特権を持ったプログラムを開始し、その後2番目のプロセスをフォークし、そのプロセスが全ての権限を返上してから大部分の仕事をする、というものです。

こうしたモジュール同士がどのように通信するかに注意してください。多くのUNIXライクのシステムでは、コマンドラインの値や環境変数の値は他のユーザーからも見えるので、プロセス間で秘密裏にデータを送信するための手段としては適切ではありません。パイプはうまく動作しますが、デッドロックに陥らないように注意してください(単純なリクエスト/レスポンス・プロトコルで、両端から吐き出せるものがうまく動作します)。




上に戻る


許可される特権を最小限にとどめる

心がけるべき事としては、プログラムが実際に必要とする特権のみを許可し、それ以上は許可しないようにするということです。UNIXプロセスは基本的にユーザーやグループとなることで特権を得ます。通常、プロセスはそのプロセスのユーザーである、ユーザーやグループとして実行します。ところが「setuid」や「setgid」などのプログラムは、これらのプログラムを所有するユーザーやグループの持つ特権を獲得してしまうのです。

残念なことに、何も考えずプログラムに「setuid root」特権を与えてしまう開発者が相変わらず多いのです。そうしておけばそのプログラムにどんな特権が必要なのかを深く考える必要がないので、開発者は自分たちにとって物事が「簡単になった」というつもりなのでしょう。ところがUNIXライクのシステムでは、こうしたプログラムが本当に何でもできてしまうので、バグがセキュリティの悲劇に直結してしまうのです。

単に簡単な課題を一つ片づけたいからといって、あらゆる特権を与えるようなことをすべきではありません。むしろプログラムには最低限必要なだけの特権を与えるべきなのです。可能であれば、setuidではなくsetgidとして実行します。setgidの与える特権の方がより少ないのです。(rootではない)特別なユーザーやグループを作り、それを必要なプログラムに対して使うのです。実行可能プログラムはrootが所持し、rootのみが書き込み可能であるようにし、root以外では変更できないようにします。ファイル許可を非常に厳格なものに設定し、絶対に必要な場合を除いて、誰にも読み書きさせないようにします。また先の特別ユーザーやグループを使うようにします。これらすべての例として、ゲーム「top ten」の得点に関する標準的な取り扱い方が挙げられるかも知れません。多くのプログラムは「setgidゲーム」であって、ゲームのプログラム自体でないと「top ten」の得点を変更できません。また得点を保存しているファイルはgamesグループが所有し、書き込みもこのグループでないとできません。例え攻撃者がゲームのプログラムに侵入したとしても、攻撃者にできるのは得点ファイルを変更することだけです。それでもゲーム開発者はやはり、悪意の得点ファイルから守るようにプログラムを書く必要があります。

有効なツールの一つとして(残念ながら少し使うのが難しいのですが)chroot()システム・コールがあります。このシステム・コールは、プロセスがファイルシステムの「root」を見る時に見るものを、変更するのです。これを使おうと思ったら(使えば便利なのです)、うまく使えるまでに時間がかかることは覚悟してください。正しいアプリケーションはプラットフォームやそのアプリケーションの細部に依存するので、「新しいroot」を注意深く用意する必要があります。ただし、そのための作業は複雑です。chroot()を呼ぶにはrootである必要があり、しかも即座に非rootに変わる必要があるのです(rootユーザーはchroot環境を回避できるので、chroot環境を効果的なものにするには、root特権を返上する必要があります。)また、chrootはネットワーク・アクセスを変更しません。これは便利なシステム・コールなので、時には考慮すべきものと言えます。ただしそのためには、かなりの努力が要ることを覚悟してください。

よく忘れられてしまうツールとして、(保存、処理どちらにもありますが)リソースを制限するものがあります。これはサービス不能攻撃を制限するために特に有効です。

  • 保存に関しては、マウントしたファイルシステムのそれぞれに対してユーザー毎、またグループ毎に、保存する量に対するクォータ(制限量)またはファイル数を設定します。GNU/Linuxシステムでのこれらに関して詳しいことは、quota(1)やquotactl(2)それにquotaon(8)を見てください。クォータ・システムはどこにでも必ずあるというわけではありませんが、大部分のUNIXライクのシステムには含まれています。GNU/Linuxやその他多くのシステムでは「ハード・リミット」(絶対に超えない)と、「ソフト・リミット」(一時的には超えられる)を設定することができます。
  • プロセスに関しては、開くファイル数、プロセス数などいくつかの制限を設定することができます。こうした機能は実際に標準(例えばSingle UNIX Specification)の一部ですので、UNIXライクのシステムでは、ほとんどどこにでもあるものになりました。詳しい情報についてはgetrlimit(2)やsetrlimit(2)、getrusage(2)、sysconf(3)それにulimit(1)等を見てください。プロセスは「カレント・リミット(current limit: 現在の制限)」を超えることはできませんが、そのカレント・リミットを一杯にまで上げて「アッパー・リミット(upper limit: 上限)」にすることはできます。残念ながらややこしい用語の問題があり、間違いやすくなっています。「カレント・リミット」は「ソフト・リミット」とも呼ばれ、またアッパー・リミットは「ハード・リミット」とも呼ばれるのです。ですからクォータに関してはソフト・リミットを超えることができる一方で、あるプロセスが設定したソフト(カレント)リミットを、プロセスが超えることができないという、おかしな状況が起こりうるのです。私の助言としては混乱の無いように、プロセスの制限には用語として「カレント・リミット」、「アッパー・リミット」を使い、ソフト・リミットやハード・リミットという用語は使わないようにする、ということです。



上に戻る


特権の時間を最小にする

特権は必要な時にのみ与え、一瞬たりとも延長しない。

可能であるならば、(どんな特権であれ)当座に必要となる特権を使用し、その後ではその特権を恒久的に返上するようにします。特権が返上されてしまえば、たとえ後から新奇な手段を使っても、特権を悪用した攻撃はできません。例えば、単一root特権を必要とするプログラムは(例えばsetuid rootになることによって)rootとして開始し、その後で、もっと特権の低いユーザーとして実行するように切り替えます。これは多くのインターネット・サーバーが採用している手法です(Apache Webサーバーでも同様です)。UNIXライクのシステムでは、プログラムが勝手にTCP/IPポートの0から1023をオープンすることはできず、オープンするにはroot特権が必要です。ただし大部分のサーバーでは、ポートをオープンする必要があるのはサーバーが最初に立ち上がる時であり、その後ではもはや特権を必要としないのです。ですから一つの手法として、まずrootとして実行し、できるだけ早く特権ポートを開いてから、(そのプロセスが属する特権グループを含めて)恒久的にそのroot特権を返上するのです。また、派生した特権も返上するようにします。例えばオープンするために特別な権限を要求するようなファイルは、できるだけ早く閉じるのです。

もし恒久的に特権を返上することができないのであれば、少なくともできるだけ頻繁に、一時的に特権を返上することを考えるべきです。ただし攻撃者がプログラムの制御を奪えば、特権を再度使用可能にして悪用することができてしまうので、この方法は恒久的に特権を返上するほどには効果的ではありません。とは言え、実行するだけの価値はあります。多くの攻撃は、プログラムに与えられた特権が使用可能な間に(例えばおかしなシンボリック・リンクやハード・リンクを作ることで)その特権プログラムが意図しない何かをさせるのです。ですからプログラムが通常は特権を使用できない状態になっていれば、攻撃者はプログラムを悪用しにくくなるのです。




上に戻る


新しい機構

ここまでに説明した原則はどんなオペレーティング・システムにも適用できますが、1970年以来、UNIXライクのシステムはどれも一般的な機構としては非常に似たものになっています。これはそうした機構が使い物にならないという意味ではありません。単純さや時間というテストを経てきたことから、それなりの利点はあります。ただし最近の一部のUNIXライクのシステムでは、最低限の特権(least privilege)をサポートしているので、これについては知っておいた方が良いと思います。時間というテストを経た機構については容易に情報が得られますが、新しい機構についてはそれほど広く知られていません。そこでここでは、その中からより抜きのいくつか、FreeBSDjail()とLinux Security Modules (LSM)フレームワーク、そしてSecurity-Enhanced Linux (SELinux) について説明したいと思います。

FreeBSD jail()

先に説明した通り、chroot()システム・コールにはいくつか問題があります。例えば正しく使うのが難しく、rootユーザーになれば、やはりこのコールを回避できてしまい、またネットワーク・アクセスは全く制御しません。FreeBSDの開発者達はこうした問題に対処するため、jail()という名の新しいシステム・コールを追加することを決めたのです。このコールはchroot()と似ていますが、はるかに使いやすく、しかも効果的です。jail内部では(rootからのものを含め)すべてのリクエストはjailに制限され、プロセスはそのjailを通してしか他のプロセスと通信できません。またシステムは、rootユーザーがjailを回避しようとして使用しがちな手段をブロックするのです。jailには特定なIPアドレスが割り振られ、自身のアドレスとして他のものを使用することができません。

jail()コールはFreeBSD専用のため、現在では使用が限定されます。ただし、各種のOSS/FSカーネル間で盛んに交配(cross-pollination)が行われています。例えばこのバージョンのjailはLinux Security Frameworkを使ってLinux用に開発されました。またFreeBSD 5では、基本面でSELinuxのような機能性を持ったモジュールを含め、(TrustedBSDプロジェクトによる)柔軟なMACフレームワークを追加しています。ですから、このコールが将来もっと使われるようになっても驚くにはあたらないでしょう。

Linux Security Modules (LSM)

2001年のLinux Kernel Summitにおいて、Linus Torvaldsは困惑しました。Security-Enhanced Linux (SELinux)プロジェクトを含め、いくつか別々のセキュリティ・プロジェクトが、それぞれのセキュリティ手法をLinuxカーネルに追加するように彼に対して要求したのです。ところが多くの点で、これらの手法に互換性はありませんでした。Torvaldsにはどれが最善かを簡単には判断できなかったので、自分で判断する代わりに各プロジェクトに呼びかけ、Linux用に何らかの一般的なセキュリティ・フレームワークを協力して作るように要請したのです。そうすれば管理者はどのセキュリティ手法であれ、自分のシステムに合ったものをインストールできるわけです。Torvaldsとの暫くの議論の後、Crispin Cowanが一般的なセキュリティ・フレームワークを作るためのグループを結成しました。このフレームワークはLinux Security Modules (LSM)フレームワークと呼ばれ、現在は(カーネル・バージョン2.6時点で)標準Linuxカーネルの一部となっています。

概念的にはLSMフレームワークは非常に単純です。Linuxカーネルは相変わらず通常のセキュリティ・チェックを行います。例えばファイルに書き込みたい場合には、やはり書き込み許可が必要です。ただし、Linuxカーネルがアクセスを許可すべきかどうか判定する必要がある時には常に、その動作が問題無いものかどうかを判定するためにチェック動作も行う、つまり「フック」を通してセキュリティ・モジュールに尋ねるのです。こうしておけば他のLinuxカーネル・モジュールと同様、管理者は単に自分が使いたいセキュリティ・モジュールを選び出して使うことができます。そこから先では、そのセキュリティ・モジュールが何を許可するかを判定するのです。

LSMフレームワークは非常に柔軟に設計されているので、多くの異なったセキュリティ・ポリシーを実装することができます。実際、LSMが現実の仕事に十分使えることを確認するために、いくつか異なるプロジェクトが共同作業を行いました。例えばLSMフレームワークには内部オブジェクトが生成・削除された時にいくつかのコールが出されます。これはこうした操作を停止させるためではなく、セキュリティ・モジュールが重要なデータを追跡できるようにするためなのです。この目的のために、LSMフレームワークが重要なフックを逃すことがないように、いくつか異なる解析ツールを使った確認が行われています。このプロジェクトは大方の予想よりもずっと難しいことが分かりました。その成功は苦労の末に達成されてものです。

LSMでは設計に関して根本的な決定がなされていることを理解する必要があります。基本的にLSMフレームワークでは、ほとんどすべてのフックが、権限的(authoritative)ではなく制限的(restrictive)であるように意図的に作られています。権限的フックは絶対的な最終決断をするものです。このフックがリクエストを許可すべきだと言えば、何があってもそのリクエストは許可されるのです。それとは対照的に、制限的フックは単に追加的な制限を追加するだけで、新しい許可は与えません。理論的には、すべてのLSMフックが権限的であれば、LSMフレームワークはもっと柔軟なものになるはずです。capable()という名前の、一つのフックは権限的です。ただしこれは単に、通常のPOSIX機能をサポートするのに必要なためにそうなっているだけです。もしすべてのフックを権限的にしてしまうとLinuxカーネルに劇的な変更を加えることになり、そうした変更が受け入れられるとは考えられませんでした。

また、大部分のフックが権限的であるとすると、ごく小さなバグでも破滅的なことになり得るという懸念も大きかったのです。一方フックを制限的にしてもユーザーは驚かないでしょう(何がどうあれ、元々のUNIXの許可はそれでも普通に動作するのです)。ですからLSMフレームワークの開発者達は意図的に制限的な手法を選び、これを使用する開発者の大部分はこのフレームワークの中で作業することにしたのです。

LSMフレームワークにある他の制限についても理解しておく必要があります。LSMフレームワークはアクセス制御のみをサポートするように設計されており、監査(auditing)などのような他のセキュリティ問題には関知していません。LSMモジュールは、自分ではすべてのリクエストやその結果のログを取ることはできません。これはLSMモジュールが、それらの全てを見ることができないためです。なぜでしょうか。一つの理由としては、拒否を監査しようとした場合など、カーネルがLSMモジュールを呼ぶこともなくリクエストを拒否してしまうことがあるからです。またパフォーマンスに関する懸念から、ネットワークに対して提案されたLSMフックやデータ・フィールドは、主流のカーネルに対しては拒否されました。一部のネットワーク・アクセスの制御は可能ですが、「ラベル付き」ネットワーク・フローをサポートするには十分とは言えません。(「ラベル付き」ネットワーク・フローでは、それぞれのパケットはオペレーティング・システムが操作する別々のセキュリティ・ラベルを持っています。)これらの制限は残念ですが、一般的な考え方に影響するようなものではありません。LSMフレームワークがやがて拡張され、こうした制限が無くなるように祈りたいものです。

こうした制限はありますが、特権に制限を加えるためには、LSMフレームワークはやはり非常に便利です。Torvaldsが目標としたものはLSMフレームワークで基本的に満足されたと言えるでしょう。「私は色々なセキュリティ・グループ間の争いには興味はない。とにかくこんな争いは早く終わりにしたい。そうすれば、どのポリシーや実装が実際に使われるかは市場が決めてくれるだろう。」

つまりLinux上のプログラムに与える特権を制限したければ、自分独自のLinuxセキュリティ・モジュールを作ることもできるのです。本当に風変わりな制限を課したければ、それも必要かも知れませんし、実際それが可能なのです。ただしこれは簡単なことではありません。いずれにせよ、やはりカーネル・コードを書くのです。可能であれば、自分で独自のものを書くよりも既存のLinuxセキュリティ・モジュールの一つを使った方が無難です。LSMモジュールにはいくつかありますが、Linuxのセキュリティ・モジュールとして最も成熟したものはSecurity-Enhanced Linux (SELinux)モジュールです。では次にこれを見て行きましょう。

Security-Enhanced Linux (SELinux)の歴史

ちょっとした歴史を知っているとSecurity-Enhanced Linux (SELinux)を理解しやすくなるでしょう。それに歴史はそれ自体興味深いものです。アメリカのNational Security Agency (NSA: 国家安全局)では長年、大部分のオペレーティング・システムには限定的なセキュリティ機能しかないことに懸念を持っていました。つまるところ彼らの仕事の一つは、Department of Defense(国防総省)が使うコンピューターを、執念に燃えた攻撃者からセキュアなものにすることなのです。Windowsや大部分のUNIX、Linuxシステムを含め、大方のオペレーティング・システムのセキュリティ機構では「discretionary access control: DAC(任意アクセス制御)」機構しか実装していないことにNSAは気付いたのです。DAC機構でプログラムに何ができるかを決めるのは、単にプログラムを実行しているユーザーの身元や、ファイルのようなオブジェクトの所有権のみなのです。DAC自体が脆弱なプログラムや悪意のプログラムに対して防御が弱いので、NSAはこれを深刻な問題と捉えました。これに対応するためにNSAでは以前から、オペレーティング・システムが「mandatory access control: MAC(強制アクセス制御)」機構もサポートするように望んでいたのです。

MAC機構では、システム管理者がシステム全体に渡るセキュリティ・ポリシーを定義できるようになっています。ですからプログラムが行えることに対する制限を、ユーザーの役割やプログラムの確実さ、予想される使い方、またプログラムが使用するデータの種類など、他の要素に基づいて課せるのです。些細な例を挙げると、MACではユーザーは簡単に「機密」データを「非機密」に変更することはできません。ただし実際には、MACではさらに多くのことができるのです。

NSAは長年オペレーティング・システムのベンダーと協力して作業してきました。ところが大きな市場を持つベンダーの多くはMACの導入に興味を示さなかったのです。MACを採り入れたベンダーでも、「別製品」として扱い、通常商品とはしませんでした。問題の一因として、古い形式のMACは十分に柔軟性に富んだものでなかったことが挙げられます。

そこでNSAの研究部門はMACをもっと柔軟に、また簡単にオペレーティング・システムに組み込めるようにすべく努力を重ねたのです。彼らはMachオペレーティング・システムを使ってプロトタイプを開発し、その後「Fluke」研究オペレーティング・システムの拡張作業を後援しました。ところが全ての作業はごく小さな「おもちゃのような」研究プロジェクトを元に行われていたので、この考え方が「本物の」オペレーティング・システムで動作するとは信じてもらえませんでした。プロトタイプを試そうとする人さえほとんどおらず、実際のアプリケーションでどの程度動作するかを確認しようとする人も稀でした。NASは独自製品のベンダーにこの考え方を説得できず、またNSAはベンダー独自のオペレーティング・システムを改造するような権利も持っていませんでした。これは目新しい問題ではありません。何年も前ですが、DARPAはDARPAで働くオペレーティング・システム研究者に対して、独自オペレーティング・システムであるWindowsを使うように強制しようとしたのですが、多くの問題に直面したのです(参考文献)。

そこでNSAは今思えば当然な,ある考えを思いつきました。つまり、おもちゃではないオープンソースのオペレーティング・システムを使い、セキュリティに関しての彼らの考え方を実装して、(1)実際に動作すること、(2)具体的にどう動くかを(ソースコードを全て公開して)見せることにしたです。そして市場で主流のオープンソース・カーネル(Linux)を使い、その中に「security-enhanced Linux(セキュリティ機能強化Linux): SELinux」として、彼らの考え方を実装したのです。驚くにはあたりませんが、本物のシステム(Linux)を使うことで、NSAの研究者達はおもちゃでは経験しなかったような問題に直面させられました。例えば大部分のLinuxベースのシステムでは、ほとんどすべてのものが動的にリンクされているため、プログラムがどのように実行されるかに関して繊細な解析を行う必要があったのです(「entrypoint」や「execute」許可に関するNSAの資料を見てください)。これはそれまでの試みよりもはるかに成功しました。以前のプロトタイプに比べて、はるかに多くの人がSELinuxを使うようになりました。

SELinuxはどのように動作するか

ではSELinuxはどのように動作するのでしょう。実はSELinuxの手法は非常に一般的なものなのです。重要なカーネル・オブジェクト、つまりあらゆるファイルシステム・オブジェクトやプロセスには、それぞれに関連して「セキュリティ・コンテキスト」があります。セキュリティ・コンテキストは(例えば非機密、機密、最高機密などのような)軍用のセキュリティ・レベルに基づくものもあれば、ユーザーの役割に基づくもの、アプリケーションに基づくもの(Webサーバーが自分のセキュリティ・コンテキストを持つことができます)、その他多くのものに基づくものがあり得ます。あるプロセスのセキュリティ・コンテキストは、そのプロセスが他のプログラムを実行する時に変更できます。実際、同じユーザーが全てを開始した場合であっても、どのプログラムから呼ばれたかによって異なったセキュリティ・コンテキストで実行することができるのです。

そうするとシステム管理者は、どのセキュリティ・コンテキストにどんな特権を許可するかを規定する「セキュリティ・ポリシー」を作ります。システム・コールが呼ばれると、SELinuxは必要な特権が全て許可されているかどうかをチェックします。もし許可されていなければリクエストを拒否します。

例えばファイルを生成するには、カレント・プロセスのセキュリティ・コンテキストは親ディレクトリのセキュリティ・コンテキストに対して「search」や「add_name」の特権を持っている必要があり、また(これから生成される)ファイルのセキュリティ・コンテキストに対して「create」特権を必要とします。またそのファイルのセキュリティ・コンテキストは、そのファイルシステムに対して「associated」の特権を持っている必要があります(例えば「最高機密」ファイルを「非機密」ディスクに書き込むことはできません)。ソケットやネットワーク・インターフェース、ホストやポートなどに対するネットワーク・アクセスの制御もあります。もしセキュリティ・ポリシーがこれら全てを許可すると、SELinuxがリクエストを許可します。それ以外の場合にはリクエストは禁止されます。これらのチェックは下手をすると遅いものになりますが、(何年もの研究に基づく)最適化がいくらでもあるので、非常に高速にすることができます。

このチェックはUNIXライクのシステムにある、通常の許可ビットとは全く別のものです。SELinuxシステムで何かをするには、標準のUNIXライクの許可と、SELinuxの許可の両方が必要です。ただしSELinuxのチェックでは、伝統的なUNIXライクの許可では困難であったことがいくつも行えます。SELinuxを使うと、特別なプログラムだけを実行するようにWebサーバーを設定でき、特別なセキュリティ・コンテキストを持つファイルに対してのみ書き込むこともできます。さらに面白いことに、もし攻撃者がWebサーバーを突破してrootになっても、(適切なセキュリティ・ポリシーを設定しておけば)攻撃者はシステム全体の制御を奪うことができないのです。

さてここで問題があるのです。SELinuxを効果的に使うには、SELinuxが様々なものに対して強制する、適切なセキュリティ・ポリシーが必要なのです。大部分のユーザーは、自分たちで容易に調整できるような使いやすい起動ポリシーを必要としています。私は数年前にSELinuxの実験を始めたのですが、その当時には起動ポリシーは幼稚なもので、多くの問題を抱えていました。例えば当初あったサンプルのポリシーでは、システムにハードウェア・クロックの更新を許可しなかったのです(私は結局これを修正するためのパッチを提出する羽目になりました)。NSAが期待しているのは、ビジネスの世界で一種の商品として適切な起動ポリシーを工夫してくれないか、ということです。実際これは実現しそうです。Red Hatや一部のDebian開発者、またGentooやその他では、基本的なSELinuxフレームワークを使い、ユーザーがすぐに使い始められるような初期セキュリティ・ポリシーを作っています。実際Red HatはそのFedoraコアで、すべてのユーザーがSELinuxを使えるように計画しています。簡単なツールを使うことによって、エキスパートでなくてもいくつかの一般的なオプションを選びさえすれば、目的に合わせてセキュリティ・ポリシーが調整できるようになるはずです。Gentooにはブート可能なSELinux LiveCDがあります。大量のコーディングを必要とせずにもっと簡単にプログラムの特権を最小限に制限できるように、こうした会社の努力を望みたいものです。

さて、これで完全に輪がつながることになります。SELinuxはプログラム実行時にのみセキュリティの遷移を許可し、(一部分ではなく全体としての)プロセスの許可を制御します。ですからSELinuxを最大限に生かすためには、アプリケーションを別々のプロセスやプログラムに分解し、特権コンポーネントはごく僅かしかないようにする必要があります。そして実はこれこそが、SELinux無しでもセキュアなプログラムを開発する方法なのです。SELinuxのようなツールを使うことによって、許可される特権に対してより細かな制御ができ、従ってより強力な防御となります。ただし、細かな制御が最も効果を発揮するように、やはりプログラムは小さなコンポーネントに分割する必要があるということです。




上に戻る


まとめ

特権の制限は様々なセキュリティの問題に対抗するために重要です。バグは避けられないものなので、バグがセキュリティ問題を引き起こす可能性を最小限にとどめる必要があります。ところがセキュアなプログラムの、少なくとも一部にはセキュリティに関連したコードがあるはずなので、単純に特権を最小限にとどめ、他のことを全て無視する、というわけにはいきません。たとえセキュリティに関連した部分を最小限にとどめたとしても、そうした部分はやはり正しいものである必要があります。そして正しいものであるためには、一般的な間違いは避けるべきなのです。

前回のコラムでは、一般的な間違いの一つであるバッファー・オーバーフローについて説明しました(参考文献)。もう一つ一般的な間違いは、誤解されがちな /tmpディレクトリの問題を含めた「レース条件(race conditions)」です。次回の記事ではこのレース条件について説明し、なぜ /tmpディレクトリがそれほど頻繁に問題になるのか、またそれを修正すべく研究者達が何をしようとしているかを解説してみたいと思います。



参考文献

  • developerWorks のコラム・シリーズ、Davidによる セキュアなプログラマー を読んでください。

  • David著のSecure Programming for Linux and Unix HOWTO(2003年3月3日、Wheeler刊)では、セキュアなソフトウェアをどのようにして開発すべきかについての詳細を説明しています。

  • Internet Security Systems Security Advisory: Remote Sendmail Header Processing Vulnerability」(2003年3月3日)では、この記事で説明したSendmailの脆弱性の技術的な概要を説明しています。

  • CERT(R) Advisory CA-2003-07 Remote Buffer Overflow in Sendmail」(2003年3月3日、2003年6月9日改訂)もSendmailの脆弱性について説明しています。

  • Glenn Grahamによる「Postfix: A Secure and Easy-to-Use MTA」(2003年8月21日、OnLamp.Com)は管理者の視点から見たPostfixについて説明しています。

  • Postfix Overview - Security」はPostfixのセキュリティ手法の概要を説明しています。

  • Postfix Anatomy - Receiving Mail」はPostfixの設計の説明から始め、このプログラムがどのように分割されて特権の制限をサポートするようになったかについても説明しています。

  • J. SaltzerM. SchroederによるProceedings of the IEEEの「The Protection of Information in Computing Systems」は、セキュアなプログラムの開発方法の基本原則に関する古典的な論文です(1975年9月、v63 n9, pp. 1278-1308)。現在でも十分に応用できることには驚くばかりです。

  • Single UNIX Specification version 3はThe Open Group Base Specifications Issue 6 and IEEE Std 1003.1, 2003 Editionとしても知られていますが、「UNIXライク」のシステムが何をすべきかについて規定しています。

  • John ViegaとMatt Messier著によるSecure Programming Cookbook(2003年O'Reilly & Associates刊)では、UNIXライクのシステムで特権を返上する方法を説明した、実用的なコード断片を挙げています。

  • NT Religious Wars: Why Are DARPA Researchers Afraid of Windows NT?」は面白い記事です。お金を払った顧客からの強い圧力にもかかわらず、コンピューター・サイエンスの研究者達は自分達の研究を独自オペレーティング・システムであるWindowsの上で行うことに強く抵抗したというのです。この記事を読むと、NSAの研究者を含めてなぜそれほど多くの研究者が、研究基盤としてLinuxや*BSDカーネルを使うことにしたのかが分かります。

  • OnLamp.com article on FreeBSD Jailsにはjail()に関する情報がさらに豊富に用意されています。

  • Security-Enhanced Linux (SELinux) Web siteにはSELinuxに関する情報が豊富にあります。

  • IBM Research Security groupにはインターネット・セキュリティやJavaセキュリティ、暗号化、データ隠匿等を含め、いくつかのセキュリティ関連のプロジェクトがあります。

  • developerWorksのLinuxゾーンにはLinux開発者のための記事が豊富に用意されています。

  • Developer BookstoreのLinuxセクションではLinux関係の技術書が値引きして購入できますので、ご利用下さい。

  • Linux上で実行する、より抜きのdeveloperWorks Subscription製品の無料の試用版をダウンロードしてください。developerWorksのSpeed-start your Linux appセクションからWebSphere Studio Site DeveloperやWebSphere SDK for Web services、WebSphere Application Server、DB2 Universal Database Personal Developers Edition、Tivoli Access ManagerそれにLotus Domino Serverが入手できます。もっと手早くしたければ、ハウ・ツー記事や技術サポートが製品毎に集められていますので、ご自由に入手してください。


著者について

David A. Wheelerはコンピューター・セキュリティの専門家で、大規模・高リスク・ソフトウェア・システムの開発技術の改善に取り組んできました。Secure Programming for Linux and Unix HOWTOの著者でありCommon Criteriaの検証者です。また記事「Why Open Source Software/Free Software? Look at the Numbers!」やSpringer-Verlag刊のAda95: The Lovelace Tutorialも書いており、IEEEの書籍Software Inspection: An Industry Best Practiceの共著者、主任編集者でもあります。この記事は著者の個人的な意見であり、Institute for Defense Analyses(防衛分析研究所)の意見を表すものではありません。著者の連絡先はdwheelerNOSPAM@dwheeler.comです。




記事の評価


サイト改善のため、ご意見をお寄せください。こちらのフォームからお願いいたします。



はいいいえわからない
 


 


12345
不充分・不完全である大変素晴らしい
 


この記事を共有する

はてなブックマーク はてなブックマーク livedoorクリップ livedoorクリップ del.icio.us del.icio.us Buzzurl(バザール) Buzzurl(バザール) Choix! Choix!
Saafブックマーク Saafブックマーク FC2ブックマーク FC2ブックマーク MM/memo MM/memo ニフティクリップ ニフティクリップ Yahoo!ブックマーク Yahoo!ブックマーク
CZブックマーク CZブックマーク newsing newsing




上に戻る


    日本IBMについて プライバシー お問い合わせ