Secure Programming for Linux HOWTO David A. Wheeler, dwheeler@dwheeler.com version 1.30, 9 February 2000 高橋 聡 hisai@din.or.jp 2000/09/22 このドキュメントは Linux で安全性が求められるプログラムを書く場合に必 要になる設計と実装のしかたについて、そのガイドラインを示します。安全性 が求められるプログラムとは、接続先に存在するデータのビューアー、 CGI スクリプト、ネットワーク関連のサーバー、setuid/setgid されているプログ ラムなどです。 ______________________________________________________________________ 目次 1. 序論 2. 背景 2.1 Linux とオープン・ソース・ソフトウエア 2.2 セキュリティの原則 2.3 安全性が求められるプログラムの種類 2.4 疑い深く、こだわりが強いことは美徳です 2.5 設計と実装を行うに当たってのガイドラインとなる情報源について 2.6 このドキュメントでの表記 3. Linux のセキュリティ機能についての概要 3.1 プロセスとは 3.1.1 プロセスが持っている属性 3.1.2 POSIX ケイパビリティ 3.1.3 プロセスの作成とその操作 3.2 ファイルシステム 3.2.1 ファイルシステムの構成要素の属性 3.2.2 作成時の初期値 3.2.3 アクセス制御の属性を変更する 3.2.4 アクセス制御の属性を使うには 3.2.5 ファイルシステムの階層 3.3 System V IPC 3.4 ソケットとネットワーク接続 3.5 quota とリソースの制限 3.6 Audit(監査) 3.7 PAM 4. 入力されるものすべてを検証すること 4.1 コマンドライン 4.2 環境変数 4.3 ファイル・ディスクリプタ 4.4 ファイルの内容 4.5 CGI からの入力 4.6 その他の入力 4.7 入力制限時間と負荷レベルの制限 5. バッファオーバーフローの回避 5.1 C/C++ の危険なところ 5.2 C/C++ のライブラリによる解決策 5.3 C/C++ のコンパイル時の解決策 5.4 他の言語 6. プログラムのインタフェースと内部構成をきちんとすること 6.1 インタフェースを安全に 6.2 パーミッションを最小限に 6.3 デフォルトは安全に 6.4 フェイル・オープン 6.5 競合状態は避けましょう 6.6 信頼できる経路だけ信じること 6.7 内部の整合性をチェックするコードを使用しましょう 6.8 リソースを自主規制しましょう 7. 他のリソースを利用する場合は慎重に 7.1 正しい値でだけ呼び出すこと 7.2 システムコールの返り値はすべてチェックしましょう 8. 情報はえりすぐってフィードバックしましょう 8.1 フィードバックは最小限に 8.2 出力が溢れていたり、反応が遅い場合も対処すること 9. トピック 9.1 ロック 9.2 パスワード 9.3 乱数 9.4 暗号アルゴリズムと通信プロトコル 9.5 Java 9.6 PAM 9.7 その他 10. 結論 11. 参考文献 12. ドキュメントのライセンス 13. 日本語版謝辞 ______________________________________________________________________ 1. 序論 このドキュメントは Linux で安全性が求められるプログラムを書く場合に必 要になる設計と実装のしかたについて、そのガイドラインを示します。このド キュメントの目的は、「安全なプログラム」です。安全なプログラムとはセ キュリティの防護壁となっており、プログラム自身と同じアクセス権限を持っ ていない入力先からの入力を受け取るプログラムのことです。そのようなプロ グラムとして、接続先に存在するデータを見るためのアプリケーション、CGI スクリプト、ネットワーク関連のサーバー、setuid/setgid されているプログ ラムなどがあげられます。このドキュメントでは、Linux のカーネル自体の修 正は取扱いませんが、ここで議論される手法の多くはカーネルの修正にも有効 です。これらのガイドラインは、安全なプログラムを書くための様々な情 報(著者自身の考えも含まれています)から「教訓として学んできたこと」を整 理して、原則の集大成としてまとめ直したものです。 このドキュメントでは、安全についての保証基準やソフトウエア工学の手法、 品質保証の手法は扱いません。それらは大切なことですが、すでに他のところ で広く論じられています。これらの手法には、テスト、ピア・レビュー、コン フィギュレーション管理、フォーマルメソッドがあります。セキュリティにつ いての開発時の保証基準については、the Common Criteria [CC 1999] や the System Security Engineering Capability Maturity Model [SSE-CMM 1999] などがあります。ソフトウエア工学の手法については、Software Engineering Institute's Capability Maturity Model for Software (SE-CMM) や ISO 9000 (ISO 9001 と ISO 9001-3 と合わせて参照のこと)、ISO 12207 などに詳 しく書かれています。 訳註: o ピア・レビューとは、同じ分野の専門家たちと意見交換を行なうこと o フォーマルメソッドとは、設計を行なうに当たって、数学的(統計的)な手 法を用いる方法論 o CC 1999] という表記は、参考文献を表す このドキュメントは、ある特定の環境で動いているシステム(もしくはネッ トワーク)を安全に設定する方法を議論していません。設定方法はプログラ ムを安全に利用する上では必須の事項ですが、これ以外に安全な設定方法 について論じている文献が多数存在します。安全に Linux システムを稼働 させる方法については、Fenzi [1999]、Seifried [1999]、Wreski [1998] をはじめとして、すでに広く論じられています。 このドキュメントは、読者のみなさんがコンピュータの安全性についておおよ そ理解しており、UNIX ライクなシステムのセキュリティ・モデルや C につい ても理解していることを前提としています。また、セキュリティに関連する Linux のプログラミング・モデルについても若干ですが解説しています。 このドキュメントの原本は にあります。また Linux Documentation Project (LDP) にも含ま れています(LDP 版は、原本よりも古い可能性があります)。 このドキュメントは David A. Wheeler が著作権((C) 1999-2000 David A. Wheeler) を保持しています。また GNU General Public License (GPL) に よってその権利は保護されています。詳しいことはこのドキュメントの最後の セクションを参照してください。 このドキュメントはまず Linux の背景とそのセキュリティについて論じま す。次のセクションでは、一般的な Linux のセキュリティ・モデルについ て、プロセスやファイルシステム等を対象に、その属性と取扱い方を一通り見 ていきます。その次にこのドキュメントの中心となる Linux 上でのアプリケ ーション開発の設計と実装についてのガイドラインを説明します。この中では 下記の項目を取り上げています。 o 入力されるものすべてを検証すること o バッファオーバフローを回避すること o プログラムのインタフェースと内部構成をきちんとすること o 他のリソースを利用する場合は慎重に行うこと o セキュリティに気を配って情報をやりとりすること o その他関連事項(乱数の取得方法など) 最後に結論と参考文献でしめくくります。 2. 背景 2.1. Linux とオープン・ソース・ソフトウエア 1984 年に Richard Stallman 氏は Free Software Foundation (FSF)に て、GNU プロジェクトという、フリーな UNIX オペレーティングシステムを作 り上げるプロジェクトを立ち上げました。フリーという言葉で、Stallman 氏 は利用すること、内容(ソース)を読むこと、修正を加えること、再配布するこ とが自由にできるソフトウエアを表現しました。 FSF は数多くの便利なツー ル群を作成することができましたが、独自のオペレーティングシステムのカー ネルを思うように開発できずにいました [FSF 1998]。 1991 年に Linus Torvalds 氏が「Linux」というオペレーティングシステムのカーネルを開発し はじめました [Torvalds 1999]。このカーネルは FSF や他のツールと相まっ て、自由に改変できる、たいへん実用的なオペレーティングシステムとなりま した。このドキュメントではカーネルを指す言葉として「Linux カーネル」 を、システム全体を示す言葉として「Linux」を使用します(同様な意味で GNU/Linux という表現を使う場合が多々あります)。 様々な団体がそれぞれに、便利なツール群をこのカーネルと組み合わせていま す。この組合せを「ディストリビューション」と呼び、団体を「ディストリ ビュータ」と呼んでいます。よく知られたディストリビュータには Red Hat、Mandrake、SuSE、Caldera、Corel、 Debian があります。このドキュメ ントは特定のディストリビューションにターゲットを当てていませんが、カー ネルのバージョンが 2.2 以上で C ライブラリが glibc 2.1 以上であること を前提にしています。現在の主要なディストリビューションはすべて、この前 提を満たしています。 「フリーソフトウエア」への関心が増すにつれ、その定義と説明を行う必要性 がでてきました。世間で広く使用されている言葉は「オープン・ソース・ソフ トウエア」であり、 [OSI 1999] で詳細に定義されています。 Eric Raymond [1997, 1998] の中で、フリーソフトウエアの開発過程について、独創性に富 んだ論文をいくつか発表しています。 Linux はいわゆる UNIX と呼ばれるものからソースコードを流用していませ ん。しかしそのインターフェースは非常に UNIX ライクです。そのため UNIX で学んだ教訓はそのまま Linux にも当てはまります。もちろんセキュリティ についても同様です。このドキュメントで述べられている情報の大部分は、実 際のところ他の UNIX ライクなシステムでも役に立ちます。しかし Linux 固 有の情報も意図的に加えられています。それは Linux の持つ優れた能力を引 き出すためです。このドキュメントではあえて Linux システムに焦点を当て て、対象となるシステムを狭めています。すべての UNIX ライクなシステムを 対象にしてしまうと、ポーティングや他のシステムの機能についての詳細な検 討が必要になってしまい、結果としてこのドキュメントの量が増えてしまうた めです。 Linux は非常に UNIX ライクで、UNIX の持つセキュリティ関連のしくみを 持っています。そのしくみとは、プロセスに対するユーザやグループの ID(uid と gid)、読み/書き/実行それぞれのパーミッションを持ったファイ ルシステム、System V 由来のプロセス間通信(IPC)、ソケットベースの IPC(ネットワークを利用した通信も含む)等です。 UNIX システム一般の基本 的なセキュリティについての情報は、 Thompson [1974] と Bach [1986] を見 てください。セクション 3 では Linux のセキュリティ機構のキーポイントを 概説します。 2.2. セキュリティの原則 セキュリティの原則については、少なからず知っておく必要があります。ぜひ [Pfleeger 1997] のような、コンピュータに関わるセキュリティ全般について 書かれた書籍を読んでください。 Saltzer [1974] と Saltzer and Schroeder [1975] において、安全を保護す るためのシステム設計を行うに当たって、その原則について下記のようにまと めています。これは現在でもなお有効です。 o 特権をできるだけ持たせない。ユーザやプログラムには、できるだけ権限 を持たせないようにすること。そうすれば、攻撃者によるダメージが最小 限に抑えられる o しくみを単純に。防御システムは小さく単純明快な設計にすること o オープンな設計。防御するしくみは、攻撃者がそのしくみの知識を持って ないことに依存してはならない。逆に、そのしくみは公開されたもので、 パスワードのように比較的少ない項目 (そして簡単に変えられる)で秘密を 守れること。そうしておけば、広く第三者からチェックを受けられる。 Bruce Schneier 氏は、頭の切れるエンジニアならば、「セキュリティに関 するすべてのコードはオープン・ソースであることを強く主張する」に違 いないとしている。またそうすることで、広く第三者からレビューを受け られ、そこで問題となった部分も修正されることを証明してい る。[Schneier 1999] o 完全に仲介を行うこと。すべてのアクセスをチェックしなければならな い。チェックするしくみは、それが破られないところに置くこと。たとえ ば、クライアント-サーバー・モデルであれば、サーバー側ですべてのアク セスをチェックする必要がある。それはユーザが、クライアント側を新し く作成したり、既存のものを修正することが可能なためである o パーミッションを活用すること。デフォルトではサービスを拒否すること o 権限を集中させない。対象へのアクセスに当たって、理想的には複数の条 件をつける必要がある。そうすれば、もしある防御システムが破られて も、無制限なアクセスを許すようなことにはならない o 共通したしくみはできるだけ用いない。しくみを共通化すると、そこが一 連の情報の流れの中で危険性をはらんだ経路になってしまう恐れがある。 したがって物理的にも論理的にも独立させること o 簡単に使える。ユーザが利用を敬遠しないように、簡単に使えるようにす ること 2.3. 安全性が求められるプログラムの種類 安全性は多岐に渡るプログラム(このドキュメントで定義されている)に求めら れています。代表的なものをあげてみます。 o リモートにあるデータを見るためのアプリケーション。ビューアー(ワード プロセッサやファイルフォーマットを見るためのビューアーなど)として使 われるプログラムでは、離れたところにいる信頼できないユーザがデータ を送るように要求するケースが多い(このような要求は Web ブラウザが自 動的に行っている場合がある)。信頼できないユーザからの入力によって、 任意のプログラムを動かすようなアプリケーションは決して許可すべきで はない。初期化マクロ(データを表示する時に動く)をサポートすること も、一般的によいとはいえない。仮にサポートしなければならない場合で も、安全なサンドボックス(複雑で間違いが起きがち)を用意する必要があ る。後程触れるバッファオーバーフローのような問題は、十分に注意が必 要である。バッファオーバーフローが起きると、信頼できないユーザが ビューアー経由で任意のプログラムを動かすことを許してしまう恐れがあ る 訳註:サンドボックス(sandbox)とは、制限付きで保護されたメモリー領 域。この領域で動くアプリケーションは、システムにダメージを与えない ように設計、動作します。 o システム管理者(root)が使用するアプリケーション・プログラム。そのよ うなプログラムでは、システム管理者以外が変更できる情報を信頼しては いけない o ローカルのサーバー(デーモンと呼ばれてる) o ネットワークサービスを行うサーバー(ネットワーク・デーモンと呼ばれる こともある) o CGI スクリプト。 CGI スクリプトは、ネットワークサービスを行うサーバ ーとしては特殊な例に当たる。しかしよく使用されているので、独立した 分野として扱うことにする。 Web サーバーが CGI スクリプトを動かす。 攻撃の内いくつかのものは Web サーバーがフィルタリングするが、CGI ス クリプト側で対処しなければならない攻撃も数多くある o setuid/setgid されたプログラム。これらのプログラムは、そのマシンを 使っているユーザが実行する。実行されるとそのプログラムのオーナーや オーナーの所属するグループの権限が与えられる。様々な理由で、安全面 からするとこれらは非常にやっかいなプログラムである。というのも、入 力の大部分は信頼できないユーザが操っており、中には誰が入力したのか わからないものもある このドキュメントでは、上記の異なった種類のプログラムの問題点を一切合財 まとめてしまいます。このやり方の欠点は、指摘された問題の中にはすべての 種類のプログラムに当てはまるとは限らないものも含まれているということで す。特に setuid/setgid されたプログラムは、予想できないような入力を受 け取るため、ガイドラインのいくつかは setuid/setgid されたプログラムに しか当てはまりません。しかし実際はそんなに割り切れるものではありませ ん。というのも、ある種のプログラムはいくつかの範疇にまたがっているから です(たとえば、 CGI スクリプトは setuid/setgid されているかもしれない し、setuid/setgid と同様な効果が出るように設定されているかもしれませ ん)。プログラムの種類すべてをまとめて考えることの長所は、プログラムの 分類を間違えたりすることなくすべての問題を検討できる点にあります。これ から見ていくことになりますが、原則の多くは安全性が必要となるプログラム すべてに当てはまります。 このドキュメントは、C で書かれたプログラムに多少かたよる傾向にあります が、 C++ や、Perl、Python、Ada95、Java などについても多少は触れていま す。これは C が 安全なプログラムを Linux で実装するのに最もポピュラー な言語だからです(CGI スクリプトは例外です。Perl がよく使われていま す)。他の言語であっても、その実装は C で行っている場合がほとんどです。 だからといって、C が安全なプログラムを書くための「最良の」言語であるわ けではありません。ここで述べられている原則の多くは、使用されているプロ グラミング言語によらず適用できます。 2.4. 疑い深く、こだわりが強いことは美徳です まず安全性が求められるプログラムを書くに当たってやっかいな点は、その着 眼点が普通のプログラムと違うところです。簡単にいうと、疑い深く、こだわ りを強く持つ必要があるということです。というのも、エラー(欠陥とかバグ とも呼ばれています)が生じた時に、システムに与える影響が普通のプログラ ムとはまったく違うからです。 安全性が求められない普通のプログラムは、エラーをたくさん抱えています。 もちろんこれらのエラーは好ましくないものですが、たいていはほとんど起こ らないものだったり、起こったとしても非常にまれなケースだったりします。 仮に起こったとしても、ユーザは偶然に出くわしてしまったはずで、そのバグ を何とか避けながら利用し続けようとすると思います。 安全性が求められるプログラムでは、この状況が一変します。とあるユーザ は、意図的にバグを捜し出して、本当にまれにしか起こらない状況をつくり出 します。そして攻撃することによって不当な権限を得ようとします。つまり、 安全なプログラムを書くのに当たっては、疑い深く、こだわりを強く持つこと が美徳になるのです。 2.5. 設計と実装を行うに当たってのガイドラインとなる情報源について 安全性が求められるプログラムを書くため(もしくは既存のプログラムのセ キュリティ上の問題点を見つけるため)に、様々なドキュメントが書かれてい ます。これらのドキュメントは、これからこのドキュメントで明らかにしてい くガイドラインの根拠になっています。 汎用的なサーバーや setuid/setgid されたプログラムを対象に、数多くの役 に立つドキュメントがあります(しかし中には参考文献がないと見つけること が困難なものもあります)。 AUSCERT(オーストラリアのコンピュータ緊急対策 チーム)はプログラミングに当たってのチェックリスト [AUSCERT 1996] を公 開しています。このチェックリストは suid されたプログラムやネットワーク 関連のプログラムをいかに安全にするかについて論じた [Garfinkel 1996] の 22 章の部分をベースにしています。 Matt Bishop [1996, 1997] でこのト ピックに関連して、非常に有益なドキュメントを発表しています。 Galvin [1998a] では、安全が必要とされているプログラムの開発のためのシンプルな 開発プロセスとチェックリストについて記述しています。後に Galvin [1998b] でチェックリストのアップデートを行っています。 Sitaker [1999] では「Linux security audit」(Linux セキュリティ監査)チームが調査する問 題に関してのリストを提示しています。 Shostack [1999] ではセキュリティ を重要視するコードをレビューする場合のチェックリストを上記とは別に提示 しています。 The Secure Unix Programming FAQ も役に立つ内容です [Al- Herbish 1999]。 Ranum [1998] からも有益な情報がいくつか得られます。推 奨されていることの中には、注意が必要なものもあります。たとえば Anonymous [unknown] では、通常でも起こりうる危険な競合状態を起こり得な いものとして、access(3)の使用を推奨しています。 Wood [1985] の中の 「Security for Programmers」の章は役に立ちますが、少々古い内容になって しまいました。 Bellovin [1994] と FreeBSD [1999] にも役に立つガイドラ インがあります。 Web とのインターフェースとなる CGI(Common Gateway Interface)について は、プログラミングをする際に必要になるセキュリティのガイドラインを示し たドキュメントが多数あります。Gundavaram [unknown]、Kim [1996]、Phillips [1995]、 Stein [1999]、Webber [1999] などがあげられま す。 別の観点(つまり「システムをクラックするには」等)からこの問題を扱ったド キュメントもたくさんあります。たとえば McClure [1999] がそれにあたりま す。インターネットの利点を生かして、他にも数え切れないほどの資料があふ れています。 このドキュメントは、有益に違いないと私が判断したガイドラインをまとめま した。そのため、考えられるすべてを網羅したものではありません。私自身が 編集したもの(おまけにリストそれぞれが独自の構成を持っています) です し、 Linux 固有のガイドライン(たとえばケイパビリティについてや fsuid の値等)についても同様です。上記すべてのドキュメントを是非参照してくだ さい。 訳註:ケイパビリティとは、オペレーティングシステムやハードウェア (CPU)が持つ、セキュリティやアクセス・コントロールを実現するしくみ。 fsuid とは、ファイルシステムをチェックする場合に使用するユーザー識別機 能。 「他人のドキュメントを引用するだけでなく、自分でドキュメントを書いたの はなぜですか?」という疑問をお持ちになったかもしれません。理由はいくつ かあります。 o 情報の多くがあちこちに分散してしまっている。重要な情報は、整理して 1 つのドキュメントとしてまとめておくと便利 o 中には、プログラマのためではなく、システム管理者や一般ユーザ向けに 書かれたドキュメントがある o Linux に関係ないドキュメントがある。たとえば setuid されたシェルス クリプトに対しての注意点をあげてあるチェックリストが多い。しかし Linux では普通そのようなスクリプトを実行できないので、注意をうなが す必要がない o どのシステム(UNIX ライクなシステムすべて)でも適用できる項目が強調さ れている場合が多い。ポータビリティを重視するならば、Linux 固有の機 能を使用しないことが一番。しかし固有の機能を使うことで、セキュリ ティが確保できるのもまた事実である。 Linux 以外のオペレーティングシ ステムとのポータビリティが必要であっても、 Linux 固有の機能を使うこ とも選択肢として残されている o このアプローチのしかたは、何も Linux だけが行っているわけではない。 他のオペレーティングシステム、たとえば FreeBSD でもセキュリティを守 るための独自のプログラミング・ガイドが用意されている 2.6. このドキュメントでの表記 システムにあるマニュアル(man)のページは名称(番号)の形式で参照します。 番号は、マニュアルのセクション番号を表しています。 C と C++ は 「\0」(ASCII の 0)を特別扱いするので、このドキュメントでは「NIL」と表 記します。「どこも指していない」ポインタ値は、「NULL」と表記します。C コンパイラは通常、整数の 0 を NULL として扱いますが、NULL をすべての ビットが 0 という実装にするようにと C の規格が規定しているわけではあり ません。 3. Linux のセキュリティ機能についての概要 Linux のセキュリティ機能についてのガイドラインを検討する前に、プログラ マの観点でそれらの機能を理解しておきましょう。このセクションではそれら の機能について概観します。すでに理解されている場合は読み飛ばしてくださ い。 プログラミング・ガイドの多くは、Linux のセキュリティ関連の項目を軽く済 ましてしまい、大切な情報を省いてしまっています。特に「どうやって使用す るのか」をかいつまんで説明する場合が多く、その機能を使用することによっ て生じるセキュリティ上の問題については、うわべの説明にしか行っていませ ん。逆に個々の機能については、マニュアルの該当するページに詳細な情報が たくさん書かれています。しかし、マニュアルページの記述は詳細すぎて全体 像の把握を困難にしがちです。このセクションでは、そのギャップを埋めよう と思います。プログラマが使いそうな Linux におけるセキュリティのしくみ を概観します。一般的なプログラミング・ガイドよりもう少し深くセキュリ ティに関する事項に焦点を当て、さらに詳細な情報が得られるよう、参考文献 をあげたいと思います。 UNIX でプログラミングをされた方々にとっては、す でにおなじみのことですが、 Linux で拡張された機能や固有の機能もいくつ かあります。その機能にびっくりするかもしれません。このセクションではそ れらの相違点を明らかにしていきます。 まずは基本的なところから。本来 Linux とは 2 つの部分から成り立ってい て、それぞれ Linux カーネル (及びカーネル・モジュール)と「ユーザー空 間」と呼ばれています。ユーザ空間はカーネル上にあり、そこで様々なプログ ラムが動いています。ユーザがログインすると、ユーザ名はそのユーザが属し ている uid(ユーザ ID)と gid(グループ ID)を表す整数値に割り当てられま す。 uid が 0 のユーザは特別な権限(役割)を持っていて、「root」と言われ ています。 root はセキュリティ・チェックをほとんど受けることがなく、シ ステム管理を行う場合に使用されるユーザです。セキュリティから見て唯一 「対象」となるもの、それがプロセスです(つまり、いろいろなことを実行し ている正体は、プロセスそのものなのです)。プロセスは様々なデータにアク セスします。それはファイルシステム(FSO)であったり、System V のプロセス 間通信(IPC)であったり、ネットワーク・ポートであったりします。もう少し この点について、詳しく見ていくことにしましょう。 3.1. プロセスとは Linux ではユーザ・レベルでの動作をプロセスを動かすことで実現していま す。独立した「スレッド」をサポートするシステムが多いのですが、Linux で はスレッドそれぞれを複数のプロセスとして走らせて実現しているようで す(Linux カーネルは最適化をはかることによって、スレッド並の実行速度を 稼いでいます)。 訳註:Linux のスレッドはユーザ・レベルではなく、カーネル・レベルのス レッドで、カーネルがスレッドの制御を行っています。fork() と同じく子プ ロセスを起こしますが、コンテキストの何を親プロセスと共有できるかを指定 できます。 3.1.1. プロセスが持っている属性 それぞれのプロセスは、次のようなセキュリティ関連の属性を持っています。 o ruid、rgid - 実ユーザ ID と 実グループ IDのことで、プロセスを実際に 走らせているユーザを表す o euid、egid - 実効ユーザ ID と 実効グループ IDのことで、権限のチェッ クのために用いる(ファイルシステムは除く) o fsuid、fsgid - ファイルシステムへのアクセス権限をチェックするために 用いる。通常 euid、egid と等しい。この属性は Linux 独自である o suid、sgid - 保存ユーザ ID と 保存グループ ID。パーミッションを「オ ン」もしくは「オフ」にする場合に使用する。詳しくは後述する o groups - ユーザが属しているグループ(GID)のリスト o umask - 新しくファイルやディレクトリを作る場合に、そのデフォルトの アクセス制限を設定するのに使用されるビット値。umask(2)を参照のこと o スケジューリングを設定するパラメタ - プロセスはそれぞれのスケジュー リング方針にもとづいて動いており、デフォルトの方針は SCHED_OTHER で ある。 SCHED_OTHER はパラメタとして nice 値、優先度(priority)とカウ ンタを持っている。詳細は sched_setscheduler(2)を参照のこと 訳註:ここで述べられている「カウンタ」とは、プロセスの実行履歴を計 測するために用いられるカウンタを意味します。 o ケイパビリティ - POSIX で定義されているケイパビリティ情報。セキュリ ティ関連の機能として、実効、継承、許可の 3 種類の機能がある。詳しく は下記参照のこと o limit - プロセス単位にそのプロセスが使用できるリソースを制限する (下記参照) o ファイルシステムのルートの位置 - プロセスから見たルート・ファイルシ ステムの位置。chroot(2)参照のこと o 属性とプロセスが実際どのように関連しているのかを知りたければ、Linux の ソース・コードを参照してください。include/linux/sched.h で定義されてい る構造体の task_struct がキーポイントです。 3.1.2. POSIX ケイパビリティ Linux カーネル 2.2 の機能として「POSIX ケイパビリティ」がサポートされ ています。 POSIX のケイパビリティは、通常 root が持っている権限をいく つかに分割して、独自に権限の体系を再構成しています。 POSIX ケイパビリ ティは、IEEE(米国電気電子通信学会)標準のドラフトで定義されています。し たがって Linux 固有の機能ではありませんが、他の UNIX ライクなシステム で広く採用されているわけではありません。 Linux のドキュメント(このド キュメントも含め)の中で、「root の権限が必要である」と書いてあった場 合、「ケイパビリティが必要である」とほぼ同じ意味になる、とケイパビリ ティについてのドキュメントに述べられています。個々のケイパビリティにつ いて知りたい場合は、下記のケイパビリティに関するドキュメントを読んでく ださい。 ファイルシステム上にある各ファイル毎にケイパビリティが適用されることが 最終的な目標なのですが、このドキュメントを書いている時点ではまだサポー トされていません。転送機能に対するケイパビリティはサポートされています が、デフォルトでは無効になっています。カーネル 2.2.11 ではケイパビリ ティを更に身近に使いやすくするしくみである「ケイパビリティ・バウンディ ング・セット(capability bounding set)」が取り入れられました。このしく みは、システム上で稼動しているすべてのプロセスが利用できるケイパビリ ティのリストを用意します(特別な init プロセスだけが利用できるケイパビ リティもあります)。あるケイパビリティがリストにない場合、権限がどうで あれ、どのプロセスもそのケイパビリティを利用できません。この機能を使っ ている例として、カーネルモジュールの読み込みを無効にする場合があげられ ます。またうまくこの機能を活用しているツールとして、 にある LCAP があげられます。 訳註:LCAP は、カーネルがサポートしているケイパビリティを無効にするこ とによって、システムをより安全にするしくみです。 POSIX ケイパビリティの詳細については、 を参照し てください。 訳註:上記 ftp サーバーは anonymous ユーザの利用を認めていません。 を利用して ください。 3.1.3. プロセスの作成とその操作 プロセスは fork(2)もしくは vfork(2)(使用しない方がよ い)、clone(2)(Linux 独自) を使って作成します。これらのシステムコールす べては、既存のプロセスをコピーして、2 つのプロセスを生成します。プロセ スは execve(2)やそのフロントエンドをコールして、別々のプログラムを実行 できます(フロントエンドとして、exec(3)、system(3)、popen(3)を参照して ください)。 あるプログラムを実行する時にファイルに setuid ビットが立っていると、そ のプロセスの euid にはファイルの uid が設定されます。 setgid が立って いると egid にファイルの gid が設定されます。 Linux 上では、シェルスク リプトのようなスクリプト全般に対して、このようなビットの設定はされない ことを忘れないでください。このようなことがスクリプトで設定できてしまう と、セキュリティ上非常に危険なことになるからです(UNIX ライクなシステム の中には setuid されているスクリプトが動くものもあります)。例外とし て、 Perl は特別な設定をほどこすと、setuid されている Perl スクリプト が実行できるようになります。 場合によって、プロセスはいくつかある uid や gid の値を変更できます。 setuid(2)、seteuid(2)、setreuid(2)、setfsuid(2)を参照してください。特 に suid の場合は、信頼できるプログラムが一時的にその uid 値を変更でき ます。 ruid の変更もしくは euid が ruid と異なる値にした場合は suid に は新しい euid の値が設定されます。特権をもたないユーザは、自分の suid から自分の euid を、ruid から euid を、 euid から ruid を設定できま す。 fsuid プロセス属性は、NFS サーバのようなプログラムの権限を、指定された いくつかの UID のファイルシステム権限に制限できるようにするためのもの です。この際、その UID にはプロセスへシグナルを送れる許可は与えませ ん。 euid が変更されると fsuid は新しい euid の値に変更されます。fsuid は setfsuid(2)という Linux 固有のシステムコールを使って設定することも できます。 root 以外から呼び出された場合は、fsuid には現在の ruid 値、euid 値、seuid 値、あるいは現在の fsuid 値しか設定できません。 3.2. ファイルシステム ファイルシステムの構成要素(FSO)は、通常のファイル、ディレクトリ、シン ボリックリンク、名前付きパイプ(FIFO)、ソケット、キャラクタスペシャ ル(デバイス) ファイル、ブロックスペシャル(デバイス)ファイルがありま す(find(1)コマンドにその一覧があります)。これらはファイルシステムに よって制御され、ファイルシステムを構成するディレクトリ上でマウント/ア ンマウントして利用します。ファイルシステム自身は、これら構成要素とは多 少異なるアクセス制限の属性を持っていて、マウント時にオプションを設定す ることによって、アクセス制限をかけることが可能です。 3.2.1. ファイルシステムの構成要素の属性 今のところ Linux では ext2 が最も一般的なファイルシステムです。ファイ ルシステムの構成要素が持っている属性は下記の通りです。 o 所有 uid と gid - これを使って、構成要素の「所有者」を識別できる。 特別な設定をしなければ、普通所有者もしくは root だけがアクセス制限 に関する属性を変更できる o ユーザ(所有者)、グループそれ以外毎に、読み込み/書き込み/実行の権 限を表すビットがある。通常のファイルの場合は、読み/書き/実行とい う文字通りの意味を持つ。ディレクトリの場合は、「読み込み」パーミッ ションはそのディレクトリの中を見られること意味し、「実行」パーミッ ションは、別名「検索」パーミッションとも言われ、実際にそのディレク トリに入って、そこにあるものを使用することができる。「書き込み」パ ーミッションはそのディレクトリでファイルの追加、削除、変更ができ る。追加だけを許可させたい場合は、下記に説明する sticky ビットを立 てること。シンボリックリンクのパーミッションは意味を持たないことに 注意すること。意味を持つのは、シンボリックリンクを含むディレクトリ とリンク先のファイルの値だけである o 「sticky ビット」 - ディレクトリに設定されると、削除や移動は root、 ファイルの所有者、もしくはディレクトリの所有者しか行えなくなる。こ れは UNIX 一般で利用されている拡張機能だが、その他のオペレーティン グシステムでは一般的ではない。 sticky ビットは、通常のファイルに対 しては何の影響も与えない。また一般ユーザでも設定ができる。古いバー ジョンの UNIX では「save program text」ビットと呼ばれ、メモリに常駐 する(スワップアウトしない)実行形式ファイルであることを示していた が、 Linux が仮想メモリ管理を実装するにいたって、すたれてしまった o setuid、setgid - 実行形式ファイルに設定されると、実効 uid と gid に そのファイルの所有者 ID と gid が設定される(各々独立に)。この機能は すべての UNIX ライクなシステムがサポートしている。 setgid がディレ クトリに設定されると、そのディレクトリに作成されるファイルは自動的 にそのディレクトリの gid 値に設定し直される。 setgid が実行権をまっ たく持たないファイルに設定されると、そのファイルがアクセスされてい る時に、強制ロック(mandatory locking)がそのファイルにかかることを示 す(ただし、マウントしているファイルシステムが強制ロックをサポートし ていれば)。このしくみは負荷が非常に重く、UNIX ライクなシステムで広 く採用されてはいない 訳註:ファイルのロック機能には、強制ロック(mandatory locking)とアド バイザリ・ロック(advisory locking)があります。違いは、前者がカーネ ルがプロセスを監視しロック操作を行うので、プロセス間の依存関係を越 えてロックが可能です。これに対して後者は、プロセス自身がロック操作 を行うので、そのプロセスの制御外のものに対してはロックが無効となり ます。詳しくは、カーネル付属のドキュメントの mandatory.txt を参照してくだ さい。 o タイムスタンプ - ファイルシステムの構成要素には、アクセスした時間も しくは修正をかけた時間が保存されている。しかし所有者は自由にこれら の値を変更できるので(touch(1)を参照)、この情報を安易に信頼しないこ と。このしくみは、すべての UNIX ライクのシステムでサポートされてい る o 変更不可(immutable)ビット - ファイルシステムの構成要素に対していか なる変更も認めない。これは、root だけが設定と解除ができる。このしく みは、ext2 ファイルシステムだけがサポートしており、すべての UNIX シ ステム(場合によっては Linux システムでも)で利用できるわけではない o 追加限定(append-only bit)ビット - ファイルシステムへの追加だけが許 可される。これは、root だけが設定と解除ができる。このしくみは、ext2 ファイルシステムだけがサポートしており、すべての UNIX システム(場合 によっては Linux システムでも)で利用できるわけではない 上記の値の多くは、マウント時に適用されます。したがって、あるビット値が すでに値(媒体上の値が何であれ)を持っていたかのように扱われる場合もあり ます。詳しいことは mount(1)を参照してください。ファイルシステムも中に はこれらのアクセス制御値のいくつかをサポートしていない場合がありますの で、くどいようですが mount(1)を見て、ファイルシステムが何をサポートし ているのかを確認してください。 アクセス制御リスト(ACL、access control list)と POSIX ケイパビリティの 値をファイルシステムへ実装する作業が続けられていますが、標準の Linux 2.2 にはまだ入っていません。 訳註:ACL は従来の所有者、グループ等によるファイルへのアクセス制御方法 にかわって更に細かな制御を可能とするしくみです。ネットワーク上のサーバ ーに対するアクセス制限についてもこの用語が使用されています (RFC 1983)。 3.2.2. 作成時の初期値 作成する時には次のルールが適用されます。あるファイルシステムの構成要 素(FSO)が作られると(たとえば creat(2)を使って)、 FSO の uid はプロセス の fsuid に設定されます。普通、FSO の gid はプロセスの fsuid が設定さ れますが、ディレクトリに setgid ビットが立っていたり、ファイルシステム の「grpid」が設定してあったりすると FSO の gid には、ディレクトリの gid が設定されます。この特殊なケースを利用することによって、いわゆる 「プロジェクト」のためのディレクトリを作ることができます。「プロジェク ト用」のディレクトリを作るには次のようにします。まずプロジェクト用に専 用のグループを作ります。それからそのグループが所有者であるプロジェクト 用のディレクトリを作成し、setgid します。こうすると、何かファイルをそ このディレクトリに置くと、自動的にそのプロジェクトが所有者となります。 同様に、新しいサブディレクトリを setgid ビットを立てたディレクトリの配 下に作成すると(ファイルシステムの grpid も設定されていない)、新しい ディレクトリも setgid ビットが立てられます(したがってプロジェクトのサ ブディレクトリは、「期待通りの正しい動作」をします。その他のケースは、 新しいファイルに setgid はかけられていません。基本となる FSO のアクセ ス制限(読み込み、書き込み、実行)は、(要求された値に umask 値を &(ビッ ト反転) ~(論理積))して求められます。ファイルが新規に作成された状態で は、常に sticky ビットも setuid ビットもクリアされています。 3.2.3. アクセス制御の属性を変更する アクセス制御の属性の大部分は、chmod(2)か chmod(1)で設定できます が、chown(1)、 chgrp(1)、chattr(1)も参照してください。 注意して欲しいことがあります。それは Linux では root だけがファイルの 所有者を変更することができるということです。 UNIX ライクなシステムの中 には、一般ユーザも所有者の変更が行えるものがありますが、これは厄介事を 引き起こします。たとえばディスク使用量を制限しようとしたとします。その 時、一般ユーザに所有者の変更を許していると、ユーザの誰かが自分の大きな ファイルを他人の所有に変更して、その人を「被害者」にしたててしまえま す。 3.2.4. アクセス制御の属性を使うには Linux と UNIX ライクなシステムのほとんどで、読み込みや書き込みの属性の 値はファイルがオープンされた時にだけチェックされます。読み書きする度に チェックされるわけではありません。システム・コールの大多数が、これらの 属性を利用しています。というのも、ファイルシステムというものが Linux の中枢をなしているからです。これらのシステム・コールに は、open(2)、creat(2)、link(2)、unlink(2)、 rename(2)、 mknod(2)、symlink(2)、socket(2)等があります。 3.2.5. ファイルシステムの階層 長年の慣例で、「何のファイルはどこに置く」という約束事ができています。 きまりを守って、ディレクトリ階層の中に情報を格納してください。概略につ いては、hier(5)を参照してください。さらに詳しく知りたけれ ば、Filesystem Hierarchy Standard (FHS) を見てください。FHS は従来の Filesystem Structure standard (FSSTND)を 新たに書き換えたものです。 3.3. System V IPC Linux は System V 由来の IPC である、メッセージ・キュー、セマフォ、共 有メモリをサポートしています。それぞれのサービスは、下記の属性を持って います。 o 作成者や作成者が属するグループ、それ以外の者の読み書きのパーミッ ション o 作成者 uid と gid - IPC オブジェクト作成者の uid と gid o 所有者 uid と gid - IPC オブジェクト所有者の uid と gid(初期状態で は IPC オブジェクト作成者の uid と同じ) 下記のルールにもとづいて IPC オブジェクトアクセスします。 o プロセスが root の権限を持っていれば、アクセスが許可される o プロセスの euid が所有者もしくは作成者の uid と同じならば、作成者の パーミッションを見て、問題なければアクセスが許可される o プロセスの euid が所有者もしくは作成者の gid と同じ、もしくはプロセ スの属するグループの中に所有者もしくは作成者の gid と同じものがあれ ば、作成者のパーミッションを見て、問題なければアクセスが許可される o その他の場合は「その他のユーザ」のパーミッションをチェックする root もしくは 所有者や作成者の euid を持つプロセスは、所有者の uid や gid を設定でき、また削除も可能であることを忘れないでください。詳しくは ipc(5)を参照してください。 3.4. ソケットとネットワーク接続 ソケットは、情報を伝える手段として特にネットワーク越しの通信に使用され ています。 socket(2)は情報を伝えるための接続ポイントを作成し、それを表 わすディスクリプタを返します。さらに詳しいことは、socket(2)やそこから 相互に参照できる関連情報を見てください。 Linux の場合、TCP や UDP で 1024 以下のローカルなポートに接続するには、root の権限が必要であること を覚えておいてください。 (リモートにある 1024 以下のポートへの接続につ いては、特別な権限は必要ありません)。 3.5. quota とリソースの制限 Linux には、ファイルシステムの割り当て制限(quota)とプロセスのリソース 制限を行なう機能があります。この機能には、「ハードな制限」(hard limit)と「ソフトな制限」(soft limit)両方の意味があり、多少意味が異なる ので、注意が必要です。 記憶装置(ファイルシステム)の割り当て制限は、マウントポイント毎に設定が 可能で、特定のユーザやグループがそこで使用できるブロック数やファイル 数(inode数)に制限をかけられます。「ハードな」ものが制限を越えることが できないのに対して、「ソフトな」ものは一時的に制限を越えることが許され ています。 quota(1)、quotactl(2)、quotaon(8)を参照してください。 rlimit は、プロセスに対する数々の割り当て制限を実現するしくみで、ファ イルサイズ、子プロセス数、オープンできるファイル数などを扱えます。「ソ フトな」制限(現状の制限(current limit)とも言う)と「ハードな制限」 (上 限(upper limit)とも言う)があります。ソフトな制限を超えることは決してで きませんが、システムコールによってハードな制限の上限まであげることがで きます。 getrlimit()、setrlimit()、getrusage()を参照してください。 3.6. Audit(監査) 現在もっとも一般的な「監査」のしくみは、syslogd(8)です。 wtmp(5)、utmp(5)、lastlog(8)、acct(2)も参照することをお勧めします。サ ーバー・プログラム(Apache Web サーバーのようなもの)の中には、独自に痕 跡を監査するしくみを持っているものもあります。 3.7. PAM 認証が必要な時に Linux システムの大部分は Pluggable Authentication Modules (PAM: 差し替え可能な認証モジュール)を使用します。このしくみを 使うと、認証方法の構成を変更できるようになります(たとえばパスワードや スマートカード等の使用)。 PAM については、後でさらに論じます。 訳註:スマートカード(smart card)とは、プラスティックのカード上に IC や メモリなどのチップを載せたカードを指します。日本では IC カードと呼ぶケ ースが多いようです。従来の磁気カードと比べると、より多くの情報を格納で きるだけではなく、プログラムをインストールして実行することが可能である 点が大きく異なります。 4. 入力されるものすべてを検証すること 入力には、信頼できないユーザからのものもあります。そこで、使用する前に それらを検査(選別)する必要があります。まず何が正しいかを定義して、その 定義にマッチしないものすべてを拒否するようにしなければいけません。その 逆の定義のしかたをしてはいけません(何が不正かを定義し、それらを拒否す る)。なぜなら、重要なケースの定義をうっかり忘れてしまうかもしれないか らです。文字列長の最大値を制限してください(必要があるなら最小値も)。そ して、長さを超えてしまった場合でもシステムが暴走しないことを確かめてく ださい (下記のバッファオーバーフローのセクションでもう少し詳しく述べま すので、見てください)。 文字列の場合は、そのシステムにとって正しいキャラクタと正しいパター ン(たとえば正規表現など) を明らかにしておき、その形式に合わないものす べてを拒否するようにしてください。文字列にコントロールキャラクタ(特に 改行や NIL)やシェルのメタキャラクタが含まれている場合、普通の文字列で は起こり得ない問題が生じます。問題を避けるために、そのようなメタキャラ クタが入力されたらすぐに「エスケープ」して、間違ってプログラムに送られ ることがないようにするのが一番です。 CERT はこの考え方をさらに推し進め て、エスケープする必要がないキャラクタの一覧に載っていないものすべてを エスケープすることを推奨しています [CERT 1998, CMU 1998]。詳細について は、下記の「正しい値でだけ呼び出すこと」を参照してください。 数字すべてに対して、許容できる最小値(たいていはゼロ)と最大値を設けま しょう。ファイル名はチェックしなければいけません。一般的に「..」(上位 ディレクトリ)を正しい値と見なしてはいけません。ファイル名を表わす場合 には、ディレクトリの変更となる動作をどんな場合でも禁止することが一番で す。たとえば、「/」を正しいキャラクタの仲間に入れてはいけません。電子 メールのアドレスを完全にチェックすることは、現実的にとても困難です。と いうのも、すべてのケースを真面目にサポートしようとすると、アドレスの中 には正しい形式ではあるものの、非常に複雑な検証を必要とするものが存在す るからです。もしそのようなチェックが必要なら、詳細は mailaddr(7)と IETF RFC 822 [RFC 822] を見てください。 訳註: IETFは、Internet Engineering Task Force の略称で、インターネッ トに関連する技術の標準化を進めるために設立された団体です。ここが発行す る文書が RFC(Requests For Comment)です。 これらのテストは 1 箇所で集中して行なうようにしてください。そうすれば 後でこのテストに間違いがないかの調査を簡単に済ませられます。 正しい入力をチェックするテストが、本当に予定した通りに動作するかを確認 してください。別のプログラムが使う入力(ファイル名や電子メールアドレ ス、URL 等)をチェックする場合には特に重要です。これらのプログラムは、 見落としがちな間違いを抱えていることが多く、いわゆる「代理人問題」(デ ータを実際に使用するプログラムとチェックするプログラムの前提条件が異 なっているケース)です。 下記のサブセクションでは、プログラムに対する様々な入力について論じま す。この入力には環境変数や umask 値など、プロセスが持っている状態も含 む点に注意してください。必ずしもすべての入力が信頼できないユーザによっ て行なわれているわけではありません。注意する必要があるのは信頼できない ユーザからの入力だけです。 4.1. コマンドライン プログラムの中には、入力のインターフェースとして、コマンドラインを使用 するものが多数あります。この場合、引数を渡すことによって入力とします。 setuid/setgid されたプログラムは、信頼できないユーザからコマンドライン による入力を受け取る場合があるので、そのプログラム自身で対処する必要が あります。一般的にユーザは、コマンドラインを自由に扱えます(execve(3)の ようなシステムコールを使って)。したがって、setuid/setgid されたプログ ラムは、コマンドラインからの入力を検査する必要があり、コマンドラインの 引数 0 番に当たるプログラム名を信用してはいけません(ユーザは NULL を含 むどんな値も設定できるからです)。 4.2. 環境変数 環境変数は、デフォルトでは親プロセスから継承されます。しかしあるプログ ラムから他のプログラムを実行(exec)した場合、環境変数に任意の値を設定で きます。 setuid/setgid されたプログラムでは、これは危険をともないま す。というのもプログラムを呼び出すことで環境変数のコントロールが可能に なり、環境変数を他のプログラムに渡せてしまうからです。普通、環境変数は 継承されてしまうため、この危険性も同時に引き継がれてしまいます。 環境変数は、同じフィールドに複数の値を設定できる形式で記憶されています (たとえば SHELL 変数には、2 つの値を設定できる)。コマンドシェルの代表 的なものは、この設定ができないようになっていますが、クラッカーは、その ような状況を作り上げられます。つまりこのケースならば、プログラムで 1 つの値はチェックしますが、実際は別の値を使用してしまうことが考えられま す。さらに悪いことに、ライブラリやプログラムはたいていの場合環境変数に よって制御されているものの、その方法があいまいだったり、わかりにくかっ たり、中にはドキュメント化されていないものがあったりします。たとえ ば、IFS 変数は sh や bash でコマンドラインの引数を分割するのに使用され るキャラクタを指定するために利用されています。シェルは低レベルのシステ ムコールを利用して呼び出されるため、IFS 変数に異常な値を設定すると、一 見安全と思われるシステムコールを危険なものに変えてしまう恐れがありま す。 setuid/setgid されたプログラムを安全にするには、環境変数の中から入 力(もしあれば)に必要とされるものを注意を払って選び出し、短いリストを作 る必要があります。そして環境変数全体を表す大域変数である environ に NULL を設定して、環境変数全体を削除し、その後に必要となる最小限の安全 な値を再設定してください (ユーザの設定値は使用「しない」こと)。環境変 数には、PATH(プログラムのありかを検索するディレクトリのリストです。こ れにカレント・ディレクトリを入れては「いけません」)、IFS(デフォルトで は「\t\n」です)、TZ(タイムゾーン)があります。 4.3. ファイル・ディスクリプタ プログラムには「オープンしたファイル・ディスクリプタ」、つまりあらかじ めオープンされているファイルが渡ります。 setuid/setgid されたプログラ ムでは、ユーザがあるファイルをオープンして、それを利用できてしまう(パ ーミッションの制限内で)ということを気にする必要があります。 setuid/setgid されたプログラムでは、新しくオープンしたファイルが常に固 定したファイル・ディスクリプタ ID に割り当てられていると想定してはいけ ません。また端末が標準入力、標準出力、標準エラー先になっていること、ま た端末がすでにオープンされていることも前提にしてはいけません。 4.4. ファイルの内容 あるファイルの内容によって、プログラムの動作が左右される場合、信頼でき るユーザだけがその内容を変更できるのでなければ、そのファイルを信用して はいけません。つまり、信頼できないユーザが、ファイルやそのファイルがあ るディレクトリ、その親ディレクトリを修正できてはいけません。そうでなけ れば、そのファイルを信頼するに値しないものとして扱わなければなりませ ん。 4.5. CGI からの入力 CGI からの入力は、実際のところ環境変数や標準入力として扱われます。した がってこれらも検証しなければなりません。 CGI からの入力の多くが、いわゆる「URL エンコードされた」形式になってい る点が検証をより厄介にしています。つまり 16 進数の HH というバイト値を 表すには %HH という形式をとります。 CGI や CGI ライブラリは、これらの 入力を適切にデコードして、バイト値が正しいかどうかをチェックする必要が あります。 %00 (NIL) や %0A (改行)のような疑わしい値を含むすべての入力 を間違いなく処理しなければいけません。入力のデコードは 1 回だけにして ください。でないと、「%2500」のような入力が誤って処理されてしまいま す(まず %25 が「%」に変換され、その結果「%00」が間違って NIL キャラク タに変換されてしまいます)。 入力に特殊なキャラクタを混ぜることで、CGI スクリプトを攻撃するケースが まま見られます。上記の解説を見てください。 HTML のフォームには、クライアント側でチェックをすることで不正な値を排 除するものもあります。これはユーザにとっては有益かもしれませんが、セ キュリティ上は無意味です。というのも、攻撃者はそのような「不正」な値を 直接 Web サーバーに送り付けられるからです。後で(「信頼できる経路だけ信 じること」のセクション)説明しますが、サーバーは自分が受け取るすべての 入力をチェックする必要があります。 4.6. その他の入力 プログラムは、入力のすべてをコントロールすることが必須です。しかし setuid/setgid されたプログラムでは困難を極めます。理由は、そのような入 力があまりに多いからです。一方、入力プログラムでは下記の点を考慮する必 要があります。 o カレントディレクトリ o シグナル o メモリー・マップ(mmap) o System V 由来の IPC o umask(新規にファイルを作成する場合のデフォルトのパーミッションを決 定する) プログラムを起動する時にディレクトリを(chdir(2)を使用して)変更する 場合は、フルパス指定できちんと目的のディレクトリに移動することも考 慮してください。 4.7. 入力制限時間と負荷レベルの制限 タイムアウトと負荷レベルの制限を設けてください。特にネットワーク経由で やってくるデータには必ず制限をかけてください。そうしないと攻撃者は絶え ることなくサービス要求を送り付けることで、いとも簡単にサービス妨害攻撃 を実行できます。 5. バッファオーバーフローの回避 「バッファオーバーフロー」は、セキュリティの欠陥として頻繁に発生しま す。技術的にはプログラムの実装上の問題ですが、あまりに頻繁に発生し、か つ重大な問題を抱えているので、あえて独立して項目を立てました。この問題 がいかに重要かは、CERT の勧告の内 1998 年の 13 の内の 9、1999 年の少な くとも半分以上がバッファオーバーフロー関連であることで明らかです。 Bugtraq による非公式な調査でも、おおよそ 2/3 の回答がバッファオーバー フローがセキュリティの脆弱さの原因としています(残りの回答は「設定ミ ス」が原因としています) [Cowan 1999] 訳註:Bugtraq は、セキュリティ関連の情報をやり取りする ML です。 ML の アーカイブ が公開され ています。 バッファオーバーフローが発生するのは、固定長のバッファ領域にある値(文 字列など)を、その領域を越えて書き続けてしまう場合です。これらの現象 は、ユーザからの入力をバッファに読み込む時にも起こりますし、プログラム のまったく違った処理の最中でも起こる可能性があります。 安全性が求められるプログラムでバッファオーバーフローを許してしまうと、 往々にして攻撃者に悪用される恐れがあります。バッファが C のローカル変 数で実装されていた場合、攻撃者はその関数の中で望みのコードを強制的に実 行させる手段としてオーバフローを利用できてしまいます。バッファがヒープ 領域にあっても、状況が改善するわけではありません。攻撃者は、この状態で もプログラム中の変数をいじることができます。さらに詳しいことは、Aleph1 [1996]、Mudge [1995]を参考にするか、 にある「Stack Smashing Security Vulnerabilities」を見てください。 訳註:ヒープ領域は、プログラムで利用するデータを格納する領域で、利用時 に動的に割り当てられ、利用が済むと解放された後、再利用に回されます。 C では、auto 変数や malloc(3) で確保された領域がこれに当たります。 プログラム言語の中には、そもそもこういった問題に影響されないものもあり ます。つまり自動的に配列の大きさを調整したり(たとえば Perl)、バッファ オーバーフローを見つけだし、防ぐしくみを標準で備えているもの(たとえば Ada95)があります。残念なことに、 C はバッファオーバーフローを防ぐ手段 をまったく持っておらず、 C++ でもたわいなくこの問題を発生させることが できます。 5.1. C/C++ の危険なところ C ユーザは、確保されている領域を越えることはありえないと確証できなけれ ば、境界をチェックしない危険な関数を使うべきではありません。通常使用を 避けるべき関数には、strcpy(3)、strcat(3)、sprintf(3)や gets(3) があり ます。その代わりに strncpy(3)や、strncat(3)、snprintf(3)や fgets(3)を 使用することを勧めます。詳しくは下記で論じます。 strlen(3)は NIL キャ ラクタが終端にあることを仮定しているので、NIL が必ず存在すると確信でき なければ、使用は避けるべきです。その他にもバッファを越えてしまう恐れの ある関数(その使い方によりますが) に は、fscanf(3)、scanf(3)、vsprintf(3)、realpath(3)、getopt(3)、getpass(3)、 streadd(3)や strecpy(3)、strtrns(3)等があります。 5.2. C/C++ のライブラリによる解決策 C/C++ での解決策として、バッファオーバーフローの問題を抱えていない関数 ライブラリの使用があげられます。 C でバッファオーバーフローを防ぐ「常套」手段として、これらの問題を抱え ていない標準ライブラリ関数を使用することがまずあげられます。この解決方 法は strncpy(3)と strncat(3)という標準関数にとても依存しています。この 解決策をとるなら、その使い方が意外と面倒で、正しく使うことが難しいこと に注意が必要です。 strncpy(3)はコピー先の文字列の終端に NIL をセットし ないので、コピー元の文字列長がコピー先以上の長さならば、strncpy(3)を呼 出した後にコピー先の終端に NIL をセットすることを忘れないでください。 strncpy(3)、strncat(3)とも、書き込みできる領域の残りの大きさを引数で渡 す必要がありますが、この残量の計算をよく間違います(ここで間違ってしま うと、バッファオーバーフロー攻撃を許してしまうことになります)。どちら の関数も、バッファオーバーフローが発生したかどうかを確認する単純なしく みを持っていません。最後になりますが、代替え関数である strncpy(3)は strcpy(3)に比べて、パフォーマンスは劣ります。これは strncpy(3)がコピー 先の残り領域を 0 で埋めるためです。 一方、OpenBSD には Miller と de Raadt [Miller 1999] 両氏によって開発さ れた strlcpy(3)と strlcat(3)があります。従来のコピーと連結とは異っ た(かつ間違いにくい)インタフェースを持ち、最小限の努力で問題の解決を試 みています。ソースと関数のドキュメントは BSD スタイルのライセンスで、 から 利用できます。 他の取り組みとしては、固定長のバッファを使うかわりに、文字列すべての領 域を動的に再確保する方法もあります。この手法は一般的で、GNU プログラミ ング ガイドラインで推奨しています。その方法の 1 つとして自動的に文字列 領域の再確保を行う C のツールである Forrest J. Cavalier III 氏が開発し た「libmib allocated string functions」があります。 から利用できます。ソースは オープン・ソースの形式をとっていますが、ドキュメントはオープン・ソース ではありません。しかし自由に入手できます。 その他にも役に立つと思われるライブラリがあります。たとえば、glib ライ ブラリは広くオープン・ソースのプラットフォーム上で利用されていま す(GTK+ ツールキットは glib ライブラリを使用していますが、glib は GTK+ を使うことなしに単独で利用できます。今の時点で、glib ライブラリの関数 がバッファオーバーフローを防ぐために有効かどうかを分析して、問題ないこ とを示すことはできませんでしたが、期待できそうな感じがします。願わく ば、このドキュメントの次以降の版では glib の関数がバッファオーバーフロ ーの問題を解決できることを確認したいと思っています。 5.3. C/C++ のコンパイル時の解決策 まったく違った観点から解決をはかろうとするものに、領域の境界チェックを コンパイル時に行うものがあります([Sitaker 1999] のリストを参照してくだ さい)。私見ですが、防御にいろいろな手段を打った中の 1 つとして、そのよ うなツールは非常に有効ですが、この手法だけで防御するのは賢い手段とはい えません。理由として 2 つは上げられます。まず、そのようなツールは必要 な防御の一部しか行うことができません(そして「完璧な」防御を行おうとす ると、通常の 12 から 30 倍遅くなります)。C と C++ はそもそもバッファオ ーバーフローを防ぐ手段を持ち合わせていません。次に、オープン・ソースで あるプログラムですと、何のツールを使ってコンパイルするかを決められてい るわけではありません。システムについてくるデフォルトの「普通の」コンパ イラを使うとセキュリティの弱点をさらすことになってしまいます。 さらに有効なツールとして「StackGuard」があります。これは「ガード」する ための値(「カナリア(canary)」と呼びます)をリターンアドレスが書かれてい る前に挿入して動作します。バッファオーバーフローが発生してリターンアド レスを書き換えると、カナリアの値が(おそらく)変更され、実際に使用される 前にシステムが検出します。これは非常に有効なのですが、リターンアドレス 以外の値(これを使用してもシステムを攻撃できます)を書き換えるバッファオ ーバーフローには対処できません。 StackGuard を強化して、カナリアを他の データに対しても使えるようにしたものが、「PointGuard」です。 PointGuard は自動的にある値(たとえば関数のポインタやロングジャンプ・ バッファ) を保護します。しかし他の変数を PointGuard を使って保護する場 合、プログラマの介在が必要となります(プログラマはどのデータをカナリア で保護しなければいけないのかを認識しなければいけない)。これは有効な半 面、本来保護すべきなのに必要がない、とうっかり判断してしまい、いとも簡 単に保護を省略してしまう場合が考えられます。 StackGuard や PointGuard、またそれと同様なものについての詳細は Cowan [1999] を参照し てください。 訳註:鳥類のカナリアは、炭鉱で一酸化炭素の増加や酸欠状態を「検知」する ために飼われていました。 これと関連して、Linux のカーネルを修正して、スタック・セグメント上での プログラムの実行を禁止してしまう方法もあります。それを行うにはパッチが 必要です (Solar Designer の パッチに含まれています。 ) このドキュメントを書いている時点で は、まだカーネルに取り込まれていません。技術的な理由の 1 つに、思った ほどその効果がでない点があげられます。攻撃者は、対象にしているプログラ ムにすでに存在している他の「面白そうな」場所 (ライブラリやヒープ領域、 スタティックなデータ・セグメント領域など)を呼び出せてしまうからです。 また Linux はスタック領域でプログラムを実行する場合があります。例とし て、シグナルや GCC の「トランポリン」の実装をする場合です。 Solar Designer の パッチでこのようなケースにも対応できますが、これがパッチを 複雑なものしている原因です。個人的には Linux 本流に組み込まれてもいい かと思います。というのもこれによっていくぶんかでも攻撃が難しくなります し、既存の攻撃のある部分は防御できるからです。しかし Linus Torvalds 氏 たちが考えているように、このパッチが見た目ほどさまざまな防御ができな い、比較的簡単にこの防御の裏をかくことができる、という点については私も 同意見です。 Linus Torvalds 氏がこのパッチを採用しない理由については、 を参照してください。 訳註:トランポリン(trampoline)とは、プログラムが実行している最中にプロ グラム自身によって生成される、互いに独立した小さなオブジェクト・コード を指します。 要するに、まずプログラムそのものでバッファオーバーフローを防ぐように開 発するのが大切です。そのように開発した後に、StackGuard のようなツール やテクニックを使って、さらに安全策を講じておくべきです。ソースコードか らバッファオーバーフローを追い出せるだけ追い出したら、 StackGuard はさ らに効果を発揮します。というのも StackGuard が防御のために呼ばれるよう な「致命的な弱点」を減らすことができるからです。 5.4. 他の言語 バッファオーバーフローは、他のプログラミング言語でも問題になっていま す。 Perl や Python、Ada95 のようなバッファオーバーフローを防ぐ言語で あってもです。 C や C++ 以外の言語を使ったとしても、もちろんすべての問 題を解決できるわけではありません。詳しくは、後程論じる「正しい値でだけ 呼び出すこと」にある NIL キャラクタの扱いを参照してください。また言語 が提供している基本的な機能(たとえばランタイム・ライブラリ)が利用できる 環境でかつその機能が安全であることを保証するという問題も残っています。 そのような問題はあるにせよ、バッファオーバーフローを防ぐよう、安全なプ ログラム開発を行う場合は、他の言語の使用を真剣に考えるべきだと思いま す。 6. プログラムのインタフェースと内部構成をきちんとすること 6.1. インタフェースを安全に インタフェースは、できる限り小さく(限りなくシンプルに)、厳密に(必要な 機能だけ)、そして例外なくそのインタフェースを使うようにする必要があり ます。信用できる入力はほとんどないと思ってください。アプリケーションや データを見るためのビューアーは、外部で作成されたファイルを表示すること が多いと思いますが、それらのファイルをプログラム(自動実行マクロも含み ます)として扱うことを避けてください。安全なサンドボックスを苦労して作 成することをいとわないのであれば、話は別ですが。 6.2. パーミッションを最小限に すでに触れましたが、この点については大原則が存在しています。それはプロ グラムには、処理のために必要な最低限のパーミッションしか持たせないとい うことです。そうすれば万が一プログラムがおかしくなっても、影響範囲が狭 まります。極端を言うと、できるなら安全性が求められるプログラムを作成す ること自体を止める、というのが一番確実なのですが。 Linux ではプロセスのパーミッションは、まずその各種 ID によって決まりま す。プロセスはそれぞれ実 ID、実効 ID、ファイルシステム ID、保存 ID を ユーザとグループ毎に持っています。これらの値をうまく使用して、パーミッ ションを最小限にすることはとても大切なことです。 別の観点からもパーミッションを最小限に抑える理由をあげられます。 o 最高のパーミッションを許可することは最小限に抑えること。なるべくな ら root の権限をプログラムに与えない。単独のファイルにアクセスする ためだけに、プログラムを setuid root しない。そのような場合はファイ ルにアクセスするために専用グループの作成を検討すること。このグルー プがファイルを所有し、プログラムはこのグループに setgid すればよ い。このようにプログラムをいきなり setuid せずに setgid してみるこ と。というのは、グループのメンバーに対しては許可されることがユーザ に対することよりも限定されているからである(たとえばファイルのパー ミッションの変更は認められない)。もしプログラムが複数のファイルにア クセスするために、複数ユーザのパーミッションを持つ必要があるなら(た とえば NFS サーバー)、 Linux 固有の機能である「ファイルシステム UID(fsuid)」を検討すること。これを採用すれば、競合状態やユーザがプ ロセスにシグナルを送れるように許可を与えることなしにファイルへのア クセスを制限できる。 どうしても root の権限をプログラムに与える必要がある場合、Linux 2.2 以上で利用可能な POSIX ケイパビリティの使用を検討すること。POSIX ケ イパビリティを利用すると、プログラムが起動するとすぐにそのプログラ ムの権限を最小限に抑えられる。 cap_set_proc(3)もしくは Linux 固有の capsetp(3)を呼び出すことで、プログラム起動とともにそのプログラムが 実際に必要とする機能だけに常に権限を制限できる。 UNIX ライクなシス テムすべてが POSIX ケイパビリティを実装しているわけではないことに注 意すること。 Linux での POSIX ケイパビリティの詳細は、 . を 参照すること o パーミッションが有効である時間を最短に。 setuid(2)、seteuid(2)やそ れと関連した機能を使用する場合は、プログラムがそのパーミッションを 必要とする時だけ有効にしているかを確認すること o パーミッションを有効にできる時間を最短に。すみやかにパーミッション を完全に放棄すること。 Linux は「保存」ID を採用しているので、信用 できない ID に対しては 2 度ばかり他の ID をセットしてしまえば、それ で終わりにできる。 setuid/setgid されたプログラムでは、特別な理由が ない限りは実効 gid と UID に実際に実行したユーザの ID をセットする こと。特に fork(2)した後は必ず。 root から他の権限に移る場合には、 必ず最初に gid を変更すること。さもないと動かなくなる! o パーミッションに左右されるモジュール数をできる限り少なく。パーミッ ションに左右されるモジュールの数がわずかなら、安全かどうかを確認す るのは容易である。方法の 1 つは前の項目で指摘したことそのままで、モ ジュールがある権限を使用し終えたら、すぐその権限を取り去る。そうす れば後から呼ばれるモジュールは権限を誤用しようがない。別のやり方は コマンドを分け、1 つはおびただしい数の処理を行う複雑なツールで権限 を持つユーザ(たとえば root)が使用するものにし、一方他のツールは setuid されてはいるが、コンパクトかつ単純なツールで限られたコマンド しか実行できないようにする(このツールで入力が認められたなら、最初の ツールに渡す)。この方法は GUI ベースのシステムにとってとても有効な 手段で、GUI 部分を普通のユーザ権限で動かし、そこで受け取ったリクエ ストを特権を持ったモジュールに渡してやる o 使えるリソースを最小限に。プログラムが書き込むことができるファイル やディレクトリをできるだけ少なくするようにパーミッションをセットす ること。これはゲームソフトのハイスコアを記録する場合によく使われて いる方法で、ゲームは普通 games に setgid されていてスコアファイルは games グループが所有している。そしてプログラム自体は別のユーザ (root など)が所有している。こうしておけば、ゲームを通じて侵入者が 入ってきてもハイスコアをいじることはできても、ゲームの実行形式や設 定ファイルには手を付けられない。 異なる機能毎にそれぞれユーザとグループを作ることを考えておくべき だ。そうしておけば、あるシステムに付け込まれると自動的に他のシステ ムもダメージを被る、ということはなくなるだろう。 chroot(2)コマンドを使えば、プログラムは限られた数のファイルしか利用 できなくなる。この機能を生かすには、ディレクトリの設定を慎重に行な う必要がある (「chroot jail(chroot の牢獄)」と呼ばれている)。 root のパーミッションを持ったプログラムは、この手を打ってもシステムを壊 せるが(mknod(2)などを呼び出してシステムメモリーを変更できてしま う)、それ以外はこの牢獄がプログラムのセキュリティを大幅に堅牢にして くれる。 オペレーティングシステムの中には、1 つのプロセスで信頼のレベルを複数持 つものもあります。たとえば Multics のリング保護機構がそれに当たりま す。一般的な UNIX や Linux では 1 つのプロセス中で信頼のレベルを複数に 分ける方法はありません。つまり、カーネルを呼び出すことでパーミッション を上げられますが、プロセスは単一の信頼レベルしか持てません。 Linux や UNIX ライクなシステムは 1 つのプロセスから複数のプロセスを fork して、 そのそれぞれのプロセスにパーミッションを設定することで、この機能をシ ミュレートすることができます。これを行なうには、安全に情報を伝達する経 路(普通は名前なしパイプが使われます) を確保し、別のプロセスを fork し てできる限り多くのパーミッションを落とさなければいけません。そして単純 なプロトコルを使って信頼性の高いプロセスから低いプロセスに要求を伝える ようにし、信頼性の高いプロセスは限られた要求しかサポートしないことを確 実に行なわなくてはなりません。 この技術は Java 2 や Fluke が強みをもつ分野の 1 つです。たとえば Java 2 はある特定のファイルだけをオープンするパーミッションというような、き めの細かいパーミッションを指定できます。しかし汎用的なオペレーティング システムでは、そのような機能は一般的に持っていません。 訳註:Fluke は、Flux プロジェクトの一環として開発されているカーネルと オペレーティングシステムの総称で、Flux μ-kernel Environment の略称で す。 nested process model にもとづき、強力で階層的なリソース管理を行 い、より安全性の高いシステムを目指しています。詳しくは、The Flux Research Group を参照してくだ さい。 Linux のプロセスには、ファイルシステム ユーザ ID(fsuid)とファイルシス テムグループ ID(fsgid)という 2 つの Linux 固有の状態変数があります。こ の変数は、ファイルシステムのパーミッションをチェックする時に使われま す。 root の権限を持つプログラムは、一般ユーザに代わってファイルにアク セスする前に fsuid と fsgid を変更することを考慮すべきです。理由は、プ ロセスに 実効ユーザ ID を設定すると、そのユーザはそのプロセスに対して シグナルを送れてしまいますが、fsuid に設定してもそうはなりません。この 方法の欠点は他の POSIX システムではこの機能が使えないことです。 6.3. デフォルトは安全に プログラムをインストールする時には、ユーザが設定する機会まですべてのア クセスを拒否すべきです。インストールされたファイルやディレクトリは、誰 もが読み書き可能であっては決していけません。要するに、信頼できるユーザ 以外は読めなくしてしまうのが一番です。設定をするための言語があるなら ば、ユーザがあえて許可しない限り、デフォルトでのアクセスは拒否すべきで す。 6.4. フェイル・オープン 安全なプログラムは常に「フェイル・オープン」であるべきです。つまり、プ ログラムが正しく動作しなくなっても、プログラムはすべてのアクセスを拒否 するように設計されている必要があります(「フェイル・セーフ」とも呼ばれ ています)。プログラムが不正と思われる行為(異常な入力や「起こり得ない」 状態になる等) を見つけたら、すぐにサービスを拒否すべきです。「ユーザが 意図することを探り出そう」などとはしないでください。ただサービスを拒否 するだけでよいのです。こうすると、時として信頼性や使い勝手が悪くなるか もしれません(ユーザの立場からすると)。しかし安全性は高まります。 6.5. 競合状態は避けましょう 安全が求められるプログラムは、要求を許可すべきかどうかを決めなければな りません。そして許可したならば、その要求を実行に移さなければなりませ ん。プログラムを実行する前に、信頼できないユーザが判定に影響を与えるど のような変更もできてはいけません。 ファイルシステムにおいては頻繁にこの問題が起こります。一般的に避けなけ ればいけないことは、プログラムが access(2)を使って要求を認めるべきかを 決定し、その後に open(2)を使うという手法です。これらのシステムコールを 発行する間に、ユーザがファイルを移動できてしまうかもしれないからです。 安全が要求されるプログラムではそうするかわりに、実効 ID とファイルシス テム ID をセットしてからすぐ、open システムコールを発行すべきです。安 全に access(2)を使う方法もありますが、その場合はユーザがそのファイルや ディレクトリをファイルシステムのルートからパスをたどっていじることがで きない時だけです。 6.6. 信頼できる経路だけ信じること 一般的に、信頼できない経路からの結果を信じてはいけません。 コンピュータで構成されたネットワーク(インターネット全体にも当てはまり ます) の大部分では、正当さが証明されていない伝送は信頼することができま せん。たとえば、インターネット上ではどんなパケットでもそのヘッダー情報 を含めて、改ざんすることが可能です。したがって、信頼できると確証できる のでなければ、その情報を第 1 の基準として、セキュリティ上の判断をしな いでください。ローカルのファイアーウォールが外部からスプーフィング(な りすまし)を防いでいるはずなので、本当に「内部」から送られたパケットで あると断言できる場合もあります。しかしファイアーウォールがおかしかった り、別の経路があったり、モバイル用の接続口があったりすると、この仮定さ えも疑わしいものになってしまいます。同様な感覚で、小さいポート番 号(1024 以下)を信頼できるものと決め込まないでください。大部分のネット ワークではそのようなリクエストは改ざん可能ですし、コンピュータシステム に、小さいポート番号の使用を認めるようにすることもできます。 標準的に使われているが本質的に安全でないプロトコル(たとえば ftp とか rlogin)を実行しているなら、デフォルトを安全にしておき、ドキュメントに は実行に当たっての前提条件を明記しておいてください。 ドメイン・ネーム・サーバー(DNS)は広くインターネット上で利用されてお り、コンピュータ名と IP アドレス(数値)の組合せを維持管理しています。 「DNS の逆引き」という方法を使えば、単純なスプーフィング攻撃の一部を排 除できますし、ホスト名を見つける時にも役に立ちます。しかしこのやり方で は認証を決めるほどの信頼性はありません。つまるところ問題なのは、DNS の リクエストが結局は攻撃者がコントロールしているどこかのシステムに対して 送られているかもしれない、というところにあります。したがって、DNS から 得られた結果が入力として正しいことを確認する必要があり、重要なアクセス 制御の手段として信用してはいけません。 パスワードを要求する場合、信頼できる入力をするために、一連の流れを設定 するように心がけてください(たとえば、ログインする前に改ざんできないキ ーを押すことを要求する、LED を点滅させて、改ざんできないパターンを表示 する等)。 電子メール(「From」に書いてあるアドレスを含む)も改ざんできます。そのよ うな攻撃の多くは、電子署名を使えば防げます。もっと簡単な防御は、電子メ ールにランダムに発生させた値を添付してやりとりする方法です。小額の金銭 取引きもないような、公開メーリング・リストへの登録ならば十分利用できま す。 信頼できないネットワーク越しに信頼できる経路を必要とするならば、何らか の暗号作成技術の助けが必要となります(最低限でも暗号的に安全なハッシュ 技術)。下記のセクションにある「暗号アルゴリズムと通信プロトコル」を参 照してください。 注意して欲しいのは、CGI があるクライアント/サーバー モデルで、クライア ントがどんな値も変更できてしまうことです。サーバー側は常にこの点に気を つけていなければなりません。例をあげると、いわゆる「隠れフィールド」、 クッキーなどは、CGI プログラムが値を受け取る前にクライアント側で値を変 更できてしまいます。クライアントが偽造できない方法で署名をするか、サー バーが署名をチェックするのでなければ、これらの値を信用してはいけませ ん。 getlogin(3)や ttyname(3)といった関数が返す値は、ローカルのユーザが制御 できてしまうので、セキュリティの用途としてこれらを信用してはいけませ ん。 6.7. 内部の整合性をチェックするコードを使用しましょう プログラムは、呼び出す時に指定する引数や想定している基本状態が適切であ ることが保証されているかをチェックすべきです。 C では assert(3)のよう なマクロが役に立つでしょう。 6.8. リソースを自主規制しましょう ネットワーク関連のデーモンでは、過負荷となる要求は拒否するか制限を設け ましょう。限界値を設定して(setrlimit(2)を使って)使用されてしまうと予想 されるリソースを制限しましょう。 setrlimit(2)を使って「core」ファイル ができないぐらいは最低限するようにしてください。普通 Linux では core ファイルを作って、プログラムが異常終了したらそのすべてのメモリを保存す るようにします。しかし core ファイルには、パスワードやその他の注意が必 要なデータがあるかもしれません。 7. 他のリソースを利用する場合は慎重に 7.1. 正しい値でだけ呼び出すこと 別のプログラムを呼び出す場合は、そのプログラムが常にパラメタとして有効 かつ事前に予想されている値だけを許可しているかを確認する必要がありま す。これは言うよりもずっと困難なことです。と言うのも、様々なライブラリ 関数やコマンドが、低レベルの関数を意外なやり方で呼び出しているかもしれ ないからです。たとえば popen(3)や system(3)のようなシステムコールのい くつかは、コマンドシェルを呼び出すように実装されています。つまりシェル のメタキャラクタがこれらのシステムコールに影響をおよぼすことを意味しま す。同様に execlp(3)や execvp(3)もシェルを呼び出すしくみになっていま す。ガイドラインの多くは popen(3)、system(3)、execlp(3)と execvp(3)を まったく使用しないように提案していて、プロセスを生成する場合には execve(3)を C 言語から直接呼び出すように提案しています [Galvin 1998b]。同様な方法で Perl や シェルのバッククォート(`)もコマンドシェル を呼び出します。 この問題の厄介な例のひとつにシェルのメタキャラクタがあります。標準的な Linux のコマンドシェルは、解釈を特別に行うキャラクタがたくさんありま す。シェルにこれらのキャラクタが渡ると、エスケープされていなければシェ ルは特別に解釈します。この方法を使ってプログラムがしばしば壊されます。 WWW Security FAQ [Stein 1999, Q37] によると、メタキャラクタは以下のも のです。 & ; ` ' \ " | * ? ~ < > ^ ( ) [ ] { } $ \n \r これらのキャラクタの内 1 つでも忘れると、悲惨なことになるかもしれませ ん。たとえば、プログラムの多くはバックスラッシュをメタキャラクタとして 扱うことを怠っています[rfp 1999]。入力の検証を説明したセクションで論じ ましたが、対策として、これらのキャラクタが入力されたらすぐにエスケープ することをお勧めします。 これと関連する問題として NIL キャラクタ(キャラクタの 0)が意外な影響を 及ぼすことがあげられます。 C や C++ の関数の大部分は、NIL キャラクタが 文字列の終端の印と想定していますが、他の言語(Perl や Ada95 など)の文字 列を扱う関数は NIL を文字列の一部として扱います。ライブラリやカーネル の呼び出しは C と同じ扱いを踏襲していますので、チェックする内容と実際 使用されることが一致していません [rfp 1999]。 他のプログラムを呼び出したり、ファイルを参照したりする時は、いつもフル パス (たとえば /usr/bin/sort のように)で指定するようにしてください。こ うすることで、「間違った」コマンドを呼び出す際に生じるエラーを無くすこ とができるだけでなく、PATH 環境変数が間違って設定されていてもエラーを 回避できます。他のファイルの参照についても、「間違った」開始パスを指定 した結果生じる問題を減らせます。 7.2. システムコールの返り値はすべてチェックしましょう システムコールでエラー状況を返せるものは、すべてそのエラー状態をチェッ クする必要があります。まず理由としてあげられるのは、システムコールのほ とんどすべてが、制限をかけられているシステム・リソースを対象としてお り、そのリソースに対してユーザはさまざまな方法で影響を与えることができ てしまう点があります。 setuid/setgid されたプログラムに は、setrlimit(3)や nice(2)のようなシステムコールを呼び出すことで、その プログラムで使用するリソースに制限をかけることができます。サーバープロ グラムを利用する外部のユーザや CGI スクリプトは同時に多量のリクエスト をサーバーに要求することで、リソースを食い潰すことができます。エラーを 適切に扱えていないならば、すでに述べた「フェイル・オープン」を参照して ください。 8. 情報はえりすぐってフィードバックしましょう 8.1. フィードバックは最小限に 信頼できないユーザに対しては、多くの情報を提供しないようにしてくださ い。ただ成功したか、失敗したかを教えて、失敗しても失敗したと言うだけに して、なぜ失敗したかについては、できるだけ教えないようにしてください。 詳細な情報はユーザの痕跡を検査したログに保存してください。たとえば、 o プログラムに何らかのユーザ認証が必要な場合(たとえばネットワークサー バーやログイン・プログラムを作成している)、認証前の段階では、ユーザ にはできるだけ情報を与えないようにしてください。特に認証前にプログ ラムのバージョンナンバーを漏らすことがないようにしてください。そう しないと、特定のバージョンのプログラムに穴があることがわかってし まった場合、ユーザがそのバージョンからアップグレードしないと攻撃者 にみすみす穴を教えてしまうことになってしまいます。 o プログラムがパスワードを要求する場合、入力を表示してはいけません。 パスワードがばれる原因の 1 つになってしまいます。 8.2. 出力が溢れていたり、反応が遅い場合も対処すること 安全性が求められるプログラムがユーザへの出力をする過程を詰まらせたり、 出力の反応を遅くさせることは、ユーザでも行なえるはずです。たとえ ば、Web ブラウザは故意に TCP/IP の経路を切断したり、反応速度を遅くした りできます。そのようなケースにも安全性が求められるプログラムは対応する べきです。特にロックはすみやかに外すようにすべきです(できれば反応を返 す前に)。そうすれば、サービス拒否攻撃(DoS 攻撃)に隙を与えないで済ませ られます。ネットワークへの書き込み要求についてはタイムアウトを常に設定 すべきです。 9. トピック 9.1. ロック プログラムが何かに対して排他的に実行する権限を持っているかどうかの裏付 けを取らなければならない状況がよくあります。 POSIX システムでは、以前 からロック状態を示すファイルを作成することで対処してきました。それは多 くのシステム間で互換性を取るにはよい方法だからです。 しかしこの方法にはいくつか避けなければならない落とし穴があります。まず root 権限を持っているプログラムは、O_EXCL モード(通常ファイルが存在し ていると失敗する)のファイルでもオープンできてしまいます。そうなると open(2)を使わず link(2)を使用してファイルを作成する必要があります。マ シン上でサーバープログラムが 1 つだけしか実行できないことを確実に行い たいなら、/var/log/名前.pid という中身がそのプログラムの pid が書かれ ているロックファイルを作成することを検討してみてください。この方法は、 プログラム予想外に中断して中途半端な状態になってしまう、という欠点を抱 えていますが、一般的に使用されており、他のシステムツールからでも簡単に 利用できます。 次に、ロックファイルが NFS でマウントされたファイルシステム上にある場 合、 NFS が通常のファイルの機能を充分にはサポートしていない問題に悩ま されることになります。 open(2)のマニュアルにどうしたらこの問題を解決で きるかの説明があります(root 権限のプログラムについての扱い方についても 説明があります) ... ロックをかけるのに「open(2)の O_CREAT and O_EXCL フラ グ」に依存しているプログラムは、競合状態に陥る問題を抱えてい ます。ロックファイルを使ってアトミックなファイルロッキングを 行うには、まず同じファイルシステム上にユニークなファイルを作 り(たとえばホスト名と pid を組み合わせます)、次にこのロック ファイルに link(2)でリンクを張り、それからユニークなファイル に対して stat(2)を行ってリンクの参照数が 2 に増えていること を確認します。 link(2)の返り値を使うのは止めてください。 9.2. パスワード できるなら、パスワードを扱うコードは自前で書かないようにしてください。 特にローカルなアプリケーションの場合、通常行うユーザのログイン認証にま かせてしまってください。アプリケーションが CGI スクリプトの場合、Web サーバーが用意している防御にまかせてください。アプリケーションをネット ワーク経由で利用するのものなら、平文でパスワードを送ることを止めてくだ さい(可能なら)。というのはネットワークを盗聴することで、いとも簡単に横 取りされて後で使われてしまうからです。ネットワークで利用するなら、少な くともダイジェスト・パスワードの使用を考えてください(直接しかけてくる 攻撃には弱いのですが、ネットワークの盗聴に対しては有効です) アプリケーションがパスワードを扱う必要があるなら、使ったらすぐ上書きし てしまってください。そうすればパスワードを見られる時間が短くなります。 Java ではパスワードを保存しておくのに String 型を使わないようにしてく ださい。 String 型は内容を変更できない型だからです(String 型は不要メモ リ領域の整理や再利用をしない限り上書きできない仕様で、今後もその仕様の ままだと思います) そのかわり char[] を使って保存してください。この方法 だとすぐにでも上書きできます。 アプリケーションでユーザがパスワードを設定できるのならパスワードを チェックして、「適切な」パスワードだけを許可してください(辞書に載って いない、一定以上の文字数である、など)。適切なパスワードの付け方を見つ けたいなら、 を見てはどうでしょうか。 9.3. 乱数 Linux カーネル(1.3.30 以上)には乱数生成機能があります。乱数生成には周 囲で発生するノイズをデバイスドライバや他の情報源から収集してエントロピ ー・プールに収めます。 /dev/random にアクセスするとエントロピー・プー ルにあるノイズから推定されたビット数の範囲でだけ、ランダムな値が返され てきます(エントロピー・プールが空の場合は、周囲からノイズが集まってく るまで、呼び出しをブロックします)。 /dev/unrandom でアクセスして、大き な値を要求すると、エントロピー・プールが使い果たされても値が返ってきま す。乱数を暗号化の目的で利用するなら(たとえばキーの生成のた め)、/dev/random を使ってください。さらに詳しい情報は、システムにある オンラインマニュアルの random(4)を参照してください。 9.4. 暗号アルゴリズムと通信プロトコル 暗号アルゴリズムと通信プロトコルは、システムの安全を維持するのに必要 で、特にインターネットのような信頼できないネットワークを経由してやりと りを行う場合は必須です。可能ならば通信セッションを暗号化し、セッション 乗っ取りの裏をかいてください。こうすれば認証情報を隠蔽でき、プライバシ ーの保護にも役立ちます。 きちんとした暗号化アルゴリズムや通信プロトコルを作り上げるには困難がと もないますので、自分で作ろうとはしないでください。そのかわりに、一般的 に信頼性が確立されている既存のプロトコルである、SSL、SSH、 IPSec、GnuPG/PGP や Kerberos を利用してください。広く公開され、長年の 攻撃に耐えてきた符号化アルゴリズムだけを使ってください (たとえばトリプ ル DES など、特許による利用の妨げがないもの)。特に、自分が暗号化の専門 家で、何をしているかを把握しているのでなければ、符号化アルゴリズムを作 成するようなことはしないでください。この種のアルゴリズムの作成は、専門 家だけに許された作業です。 関連して、どうしても独自に通信プロトコルを開発しなければならないなら、 過去に起きた問題事例の調査をしてください。 Bellovin [1989] に載ってい る TCP/IP プロトコルにおけるセキュリティについてのレビューのような古典 的な資料や Bruce Schneier [1998] が役に立つと思います。また、Mudge 氏 によるマイクロソフト社の PPTP の実装破りやその後の推移も参考になると思 います。 訳註:Mudge 氏は、L0pht Heavy Industries という超ハッカー(クラッカー? 評価が別れているようです)集団の主任科学者でした。現在は @Stake という セキュリティ関連のサービスを提供する会社で研究開発担当副社長をしていま す。 もちろん新しいプロトコルに対しては、広くレビューを行うべきで、できるな ら再利用してください。 9.5. Java Linux 上のセキュリティに関係したプログラムの中には Java や Java バー チャル・マシン(JVM)を使って実装されているものがあります。 Java で安全 性を要求されるプログラムを書くには Gong [1999] 他の資料で詳細が述べら れています。下記に Gong [1999] から抜粋したキーポイントをあげておきま す。 o public なフィールドや変数を使わないこと。利用する側に private で宣 言して提供すれば、結果としてアクセスに制限をかけられる o 特に理由がない限り private メソッドにすること o static なフィールド変数の使用は避けること。そのような変数はクラスに 従属しており(クラスのインスタンスではない)、クラスは他のクラスと相 互関係を持つ。結果として、static な変数はその変数が属していない他の クラスから参照できてしまい、安全の確保が困難になる o 不正なものとなる可能性を持ったコードに対して mutable オブジェクトを 返してはならない(そのコードが内容を変更してしまう恐れがあるため) 9.6. PAM Linux ディストリビューションのほとんどは、PAM(Pluggable Authentication Modules)を持っており、ユーザの認証に柔軟に対応できるしくみになっていま す。カーネルのバージョンが 2.2 系列である Red Hat Linux、Caldera、Debian が採用しており、FreeBSD のバージョン 3.1 も採用 しています。 PAM を使うと、プログラムと認証のしくみ(パスワードやスマー ト・カード)を独立したものにできます。つまり、プログラムは PAM を呼び出 し、PAM がローカルシステムの管理者が設定した内容をチェックし、どの「認 証モジュール」が必要かをランタイムに判断します。認証が必要となるプログ ラム(たとえばパスワードを入力する)を作成しているなら、 PAM を採用すべ きです。詳細は、Linux-PAM プロジェクトの Web サイトである、 を参照してくださ い。 9.7. その他 前提条件の少なくとも一部は、使う前にプログラムにチェックさせてください (たとえば、プログラムが開始されるところで)。たとえば、あるディレクトリ で「sticky」ビットが立っていることを前提にしているなら、本当にそうなっ ているかをテストしてください。テストに時間はかからないですし、それに よって深刻な問題を防ぐことができるはずです。もしそれぞれの呼び出しでテ スト実行時間がかかることが気になるなら、インストール時には最低限行うよ うにしてください。 監査ログはプログラム起動時やセッション開始時、動作が怪しげな時に書き込 むようにしてください。情報として考えられるものは、年月日、時 刻、uid、euid、gid、egid、端末情報、プロセス id、コマンドラインの値で す。監査ログを採るに当たっては、syslog(3)関数が参考になると思います。 インストール・スクリプトはできるだけ安全にプログラムをインストールして ください。デフォルトでは、インストールするファイルすべてを root か他の システム管理ユーザの所有にして、他のユーザが書き込みができないようにし てください。こうすれば root 以外のユーザはウイルスをインストールできま せん。 root 以外のユーザがインストールできる場所も用意しておいておけ ば、root の権限を持たないユーザやインストーラを信じきれない管理者でも プログラムを使えるようになります。 可能であれば、root に setuid や setgid されたプログラムは作らないでく ださい。ユーザには root でログインするようにさせてください。 コードに電子署名をしてください。そうすれば利用者は送られてきたものが利 用できるものかどうかをチェックできます。 安全性が求められるプログラムを作成する場合に静的にリンクを行うことを検 討してみてください。安全性が求められるプログラムが動的リンクを使わない ようにすれば、動的なライブラリのリンク機能を狙った攻撃に対抗できます。 コードを眺めている時には条件にマッチしないケースすべてを検討してくださ い。たとえば switch 文があった場合、どのケースにもマッチしなかった場合 どうなるのか?「if」文があって条件が偽だった場合、どのように処理される か? プログラムをコンパイルする時や実行する時にチェック機能を確実に働かせる ようにして、本番で動かす時もそうしておいてください。 Perl のプログラム なら警告フラグ(-w)をつけるべきです。そうすると危険になるかもしれないコ ードやすでに古い文法になってしまった式に対して警告を出してくれます。ま た汚染予防フラグ(-T)をつけると、何らかのフィルタリングをかけない限り、 信頼できない入力を直接使用できなくなります。セキュリティ関連のプログラ ムは警告をすべて有効にして警告が出ないようにコンパイルすべきです。 gcc を使って C や C++ をコンパイルするには、少なくとも下記のコンパイル時の フラグを使用してください(多数の警告メッセージを有効にして、警告すべて を潰してください)。 gcc -Wall -Wpointer-arith -Wstrict-prototypes 10. 結論 完璧に安全なプログラムを Linux 上で設計して実装するのは、本当に困難な 作業です。完璧に安全なプログラムが難しい訳は、考えられるすべての入力と 敵意を持っているかもしれないユーザがコントロールしている環境に対して、 適切に対応しなければならないところにあります。これは Linux 固有の問題 ではありません。他の汎用的なオペレーティングシステム(UNIX や Windows NT など)も開発者に対して同様な難問を突きつけています。安全性が求められ るプログラムの開発者は使用しているプラットフォームについて深く理解し て、ガイドライン(このドキュメントなど)を調べて適用し、品質を上げるプロ セスを設けて(ピア・レビューなど)、プログラムの脆弱なところを減らして行 く必要があります。 11. 参考文献 注意して欲しいのは、ここでは Web サイトで利用可能な技術文献を中心にあ げていることです。技術的な情報のほとんどが Web サイトから入手できるか らです。 [Al-Herbish 1999] Al-Herbish, Thamer. 1999. Secure Unix Programming FAQ. . [Aleph1 1996] Aleph1. November 8, 1996. ``Smashing The Stack For Fun And Profit.'' Phrack Magazine. Issue 49, Article 14. or alternatively . [Anonymous unknown] SETUID(7) . [AUSCERT 1996] Australian Computer Emergency Response Team (AUSCERT) and O'Reilly. May 23, 1996 (rev 3C). A Lab Engineers Check List for Writing Secure Unix Code. [Bach 1986] Bach, Maurice J. 1986. The Design of the Unix Operating System. Englewood Cliffs, NJ: Prentice-Hall, Inc. ISBN 0-13-201799-7 025. [Bellovin 1989] Bellovin, Steven M. April 1989. "Security Problems in the TCP/IP Protocol Suite" Computer Communications Review 2:19, pp. 32-48. [Bellovin 1994] Bellovin, Steven M. December 1994. Shifting the Odds -- Writing (More) Secure Software. Murray Hill, NJ: AT&T Research. [Bishop 1996] Bishop, Matt. May 1996. ``UNIX Security: Security in Programming.'' SANS '96. Washington DC (May 1996). [Bishop 1997] Bishop, Matt. October 1997. ``Writing Safe Privileged Programs.'' Network Security 1997 New Orleans, LA. [CC 1999] The Common Criteria for Information Technology Security Evaluation (CC). August 1999. Version 2.1. Technically identical to International Standard ISO/IEC 15408:1999. [CERT 1998] Computer Emergency Response Team (CERT) Coordination Center (CERT/CC). February 13, 1998. Sanitizing User-Supplied Data in CGI Scripts. CERT Advisory CA-97.25.CGI_metachar. . [CMU 1998] Carnegie Mellon University (CMU). February 13, 1998 Version 1.4. ``How To Remove Meta-characters From User-Supplied Data In CGI Scripts.'' . [Cowan 1999] Cowan, Crispin, Perry Wagle, Calton Pu, Steve Beattie, and Jonathan Walpole. ``Buffer Overflows: Attacks and Defenses for the Vulnerability of the Decade.'' Proceedings of DARPA Information Survivability Conference and Expo (DISCEX), To appear at SANS 2000, . For a copy, see . [Fenzi 1999] Fenzi, Kevin, and Dave Wrenski. April 25, 1999. Linux Security HOWTO. Version 1.0.2. [FreeBSD 1999] FreeBSD, Inc. 1999. ``Secure Programming Guidelines.'' FreeBSD Security Information. [FSF 1998] Free Software Foundation. December 17, 1999. Overview of the GNU Project. [Galvin 1998a] Galvin, Peter. April 1998. ``Designing Secure Software''. Sunworld. . [Galvin 1998b] Galvin, Peter. August 1998. ``The Unix Secure Programming FAQ''. Sunworld. [Garfinkel 1996] Garfinkel, Simson and Gene Spafford. April 1996. Practical UNIX & Internet Security, 2nd Edition. ISBN 1-56592-148-8. Sebastopol, CA: O'Reilly & Associates, Inc. [Gong 1999] Gong, Li. June 1999. Inside Java 2 Platform Security. Reading, MA: Addison Wesley Longman, Inc. ISBN 0-201-31000-7. [Gundavaram Unknown] Gundavaram, Shishir, and Tom Christiansen. Date Unknown. Perl CGI Programming FAQ. [Kim 1996] Kim, Eugene Eric. 1996. CGI Developer's Guide. SAMS.net Publishing. ISBN: 1-57521-087-8 [McClure 1999] McClure, Stuart, Joel Scambray, and George Kurtz. 1999. Hacking Exposed: Network Security Secrets and Solutions. Berkeley, CA: Osbourne/McGraw-Hill. ISBN 0-07-212127-0. [Miller 1999] Miller, Todd C. and Theo de Raadt. ``strlcpy and strlcat -- Consistent, Safe, String Copy and Concatenation'' Proceedings of Usenix '99. and [Mudge 1995] Mudge. October 20, 1995. How to write Buffer Overflows. l0pht advisories. . [OSI 1999]. Open Source Initiative. 1999. The Open Source Definition. . [Pfleeger 1997] Pfleeger, Charles P. 1997. Security in Computing. Upper Saddle River, NJ: Prentice-Hall PTR. ISBN 0-13-337486-6. [Phillips 1995] Phillips, Paul. September 3, 1995. Safe CGI Programming. [Raymond 1997] Raymond, Eric. 1997. The Cathedral and the Bazaar. [Raymond 1998] Raymond, Eric. April 1998. Homesteading the Noosphere. [Ranum 1998] Ranum, Marcus J. 1998. Security-critical coding for programmers - a C and UNIX-centric full-day tutorial. . [RFC 822] August 13, 1982 Standard for the Format of ARPA Internet Text Messages. IETF RFC 822. . [rfp 1999]. rain.forest.puppy. ``Perl CGI problems.'' Phrack Magazine. Issue 55, Article 07. . [Saltzer 1974] Saltzer, J. July 1974. ``Protection and the Control of Information Sharing in MULTICS.'' Communications of the ACM. v17 n7. pp. 388-402. [Saltzer 1975] Saltzer, J., and M. Schroeder. September 1975. ``The Protection of Information in Computing Systems.'' Proceedings of the IEEE. v63 n9. pp. 1278-1308. Summarized in [Pfleeger 1997, 286]. [Schneier 1998] Schneier, Bruce and Mudge. November 1998. Cryptanalysis of Microsoft's Point-to-Point Tunneling Protocol (PPTP) Proceedings of the 5th ACM Conference on Communications and Computer Security, ACM Press. . [Schneier 1999] Schneier, Bruce. September 15, 1999. ``Open Source and Security.'' Crypto-Gram. Counterpane Internet Security, Inc. [Seifried 1999] Seifried, Kurt. October 9, 1999. Linux Administrator's Security Guide. . [Shostack 1999] Shostack, Adam. June 1, 1999. Security Code Review Guidelines. . [Sitaker 1999] Sitaker, Kragen. Feb 26, 1999. How to Find Security Holes and [SSE-CMM 1999] SSE-CMM Project. April 1999. System Security Engineering Capability Maturity Model (SSE CMM) Model Description Document. Version 2.0. [Stein 1999]. Stein, Lincoln D. September 13, 1999. The World Wide Web Security FAQ. Version 2.0.1 [Thompson 1974] Thompson, K. and D.M. Richie. July 1974. ``The UNIX Time-Sharing System.'' Communications of the ACM Vol. 17, No. 7. pp. 365-375. [Torvalds 1999] Torvalds, Linus. February 1999. ``The Story of the Linux Kernel.'' Open Sources: Voices from the Open Source Revolution. Edited by Chris Dibona, Mark Stone, and Sam Ockman. O'Reilly and Associates. ISBN 1565925823. [Webber 1999] Webber Technical Services. February 26, 1999. Writing Secure Web Applications. . [Wood 1985] Wood, Patrick H. and Stephen G. Kochan. 1985. Unix System Security. Indianapolis, Indiana: Hayden Books. ISBN 0-8104-6267-2. [Wreski 1998] Wreski, Dave. August 22, 1998. Linux Security Administrator's Guide. Version 0.98. 12. ドキュメントのライセンス このドキュメントは David A. Wheeler が著作権((C) 1999-2000 David A. Wheeler) を保持しています。また GNU General Public License (GPL) に よってその権利は保護されています。自由に再配布が可能です。ドキュメント の原文を「プログラム」と見なして、下記の条件を厳守してください。 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 13. 日本語版謝辞 この翻訳を行うに当たって下記の方々にお世話になりました。この場を借りて お礼申し上げます。 o 川嶋さん o 後藤雅晴さん o 高城@長野高専さん o 千旦さん o 山下さん o 藤原さん(旧版の翻訳も参考にさせていただきました) o 水原さん