Secure Programming for Linux and Unix HOWTO

David A. Wheeler

dwheeler@dwheeler.com

高橋聡 - 日本語訳

hisai@din.or.jp

v2.962 Edition

Copyright (C) 1999, 2000, 2001, 2002 by David A. Wheeler

v2.962, 12 March 2002

この文書は、Linux および Unix システム上で安全なプログラムを書く際に必
要となる設計や実装について、そのガイドラインを提供します。遠隔のデータ
を見るためのビューアーや Web アプリケーション(CGI スクリプトを含む)、ネ
ットワーク・サーバ、setuid や setgid してあるプログラムが対象です。 C
や C++、Java、Perl、PHP、Python、TCL、Ada95 個別のガイドラインも掲載し
ます。

This book is Copyright (C) 1999-2002 David A. Wheeler. Permission is
granted to copy, distribute and/or modify this book under the terms of
the GNU Free Documentation License (GFDL), Version 1.1 or any later
version published by the Free Software Foundation; with the invariant
sections being ``About the Author'', with no Front-Cover Texts, and no
Back-Cover texts. A copy of the license is included in the section
entitled "GNU Free Documentation License". This book 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.

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

Table of Contents
1. はじめに
2. 背景
   
    2.1. Unix や Linux、オープンソースもしくはフリーソフトウェアについ
        て
    2.2. セキュリティの原則
    2.3. なぜプログラマは危ないコードを書いてしまうのか
    2.4. オープンソースはセキュリティに効果があるのか
    2.5. 安全なプログラムの種類
    2.6. 疑い深く、こだわりが強いことに価値がある
    2.7. このドキュメントを書いた訳は ?
    2.8. 設計と実装の指針についての情報源
    2.9. その他のセキュリティ情報源
    2.10. ドキュメントでの約束事
   
3. Linux と Unix のセキュリティ機能
   
    3.1. プロセス
    3.2. ファイル
    3.3. System V IPC
    3.4. ソケットとネットワーク接続
    3.5. シグナル
    3.6. Quota とリソースの制限
    3.7. ダイナミックリンク・ライブラリ
    3.8. Audit(監査)
    3.9. PAM
    3.10. Unix ライクなシステムに固有なセキュリティ拡張機能
   
4. 入力されるものすべてを検証すること
   
    4.1. コマンドライン
    4.2. 環境変数
    4.3. ファイル・ディスクリプタ
    4.4. ファイルの内容
    4.5. Web ベースのアプリケーションの入力(特に CGI スクリプト)
    4.6. その他の入力
    4.7. 自然言語(ロカール)の選択
    4.8. 文字のエンコード
    4.9. サイトにまたがった悪意あるコンテンツ(Cross-site Malicious
        Content)を防ぐ
    4.10. 再表示する可能性のある HTML や URI にはフィルタをかける
    4.11. クエリ以外の実行に HTTP の GET 命令を使わせない
    4.12. SPAM に対抗する
    4.13. 入力時間と負荷レベルに制限をかける
   
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. 1 つの構成要素の機能を最小限にする
    6.6. setuid や setgid したスクリプトを使わない
    6.7. 設定を安全にし、安全なデフォルトを使用する
    6.8. 初期値を安全にロードする
    6.9. フェイル・セーフ
    6.10. 競合状態を避ける
    6.11. 信頼できる経路だけ信じること
    6.12. 高信頼パス(Trusted Path)を設ける
    6.13. 内部で一貫性をチェックするコードを利用する
    6.14. リソースを自己制御する
    6.15. サイトにまたがって存在する悪意あるコンテンツを防ぐ
    6.16. セマンティック攻撃の裏をかく
    6.17. データの種類に気を配る
   
7. 他のリソースを利用する場合は慎重に
   
    7.1. 安全なライブラリ・ルーチンだけを呼び出すこと
    7.2. 正しい値でだけ呼び出す
    7.3. メタキャラクタを扱う
    7.4. プログラマ向けのインタフェースだけを呼び出す
    7.5. システムコールの返り値はすべてチェックする
    7.6. vfork(2)は使わない
    7.7. 組込みコンテンツの読み込み時に発生する Web バグに対処する
    7.8. 秘密にしたい情報は隠す
   
8. 情報はえりすぐってフィードバックする
   
    8.1. フィードバックは最小限に
    8.2. コメントはいれない
    8.3. 出力が溢れたり、反応が遅い場合も対処する
    8.4. データフォーマットを制御する(「書式文字列」)
    8.5. 出力時に文字符号化を制御する
    8.6. Include ファイルや設定ファイルへのアクセスを防ぐ
   
9. 言語固有の問題
   
    9.1. C と C++
    9.2. Perl
    9.3. Python
    9.4. シェルスクリプト言語(sh と csh 系)
    9.5. Ada
    9.6. Java
    9.7. TCL
    9.8. PHP
   
10. 専門的な話題
   
    10.1. パスワード
    10.2. Web の認証
    10.3. 乱数
    10.4. ユーザ空間ではとりわけ秘密(パスワードや鍵)を守る
    10.5. 暗号化アルゴリズムとプロトコル
    10.6. PAM を使う
    10.7. ツール
    10.8. Windows CE
    10.9. 監査記録を書き込む
    10.10. 物理的な漏洩
    10.11. その他
   
11. 結論
12. 参考文献
A. 履歴
B. おことわり
C. ドキュメントのライセンスについて
D. GNU Free Documentation License
E. About the Author
F. 日本語版謝辞

List of Tables
4-1. Legal UTF-8 Sequences

List of Figures
1-1. プログラム概念図

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

Chapter 1. はじめに

                                    【訳註：聖書の訳は、日本聖書協会聖 
                                    書新共同訳から引用しました。原文の 
                                    参照元である NIV(New International 
                                    Version)が改版されていたため、その 
                                    日本語版 (http://www.gospelcom.net/
                                    ibs/bibles/japanese/) は用いません 
                                    でした。以下同様です】             
                                                                       
                                    知恵ある人はひとりで勇士たちの町に 
                                    上りその頼みとする砦を落とすことも 
                                    できる。                           
                                                                       
                                               旧約聖書箴言 21 章 22 節

この文書は Linux および Unix システム上で安全なプログラムを書く際に必要
となる設計や実装について、そのガイドラインを提供します。この文書の意図
する、「安全なプログラム」とは、セキュリティの境界線上に位置し、そのプ
ログラムとは異なるアクセス権限を持つ接続元からの入力を扱うプログラムで
す。そのようなプログラムには、遠隔のデータを見るためのビューアーを使っ
たものや、 Web アプリケーション(CGI スクリプトを含む)、ネットワーク・サ
ーバ、setuid もしくは setgid してあるプログラムがあります。この文書では
、オペレーティングシステムのカーネル自体の修正は扱いませんが、これから
議論する原則はカーネルに対しても適用できる場合がよくあります。安全なプ
ログラムをどのように作成するかについて、さまざまな情報源を調べ回った「
教訓」を元に、ガイドラインとして構成し直し、広範に適用できるようにしま
した (著者の考えも加えています)。この文書はいくつかの言語、具体的には C
や C++、Java、Perl、PHP、Python、TCL、 Ada95 に固有の手引きも記載してい
ます。

この文書は、保証基準やソフトウェア・エンジニアリングの工程、品質保証か
ら見た取り組みについては触れていません。そのような指標は大切ですが、既
にあちこちで議論されています。テストやピア・レビュー、コンフィギュレー
ション管理、形式的な各種の方法がそれに当たります。セキュリティに関連し
た開発に当たっての保証基準については、 the Common Criteria [CC 1999] や
the Systems Security Engineering Capability Maturity Model [SSE-CMM
1999] に記載してあります。ソフトウェア・エンジニアリングの工程全般につ
いては Software Engineering Institute's Capability Maturity Model for
Software (SW-CMM) [Paulk 1993a, 1993b] や ISO 12207 [ISO 12207] を参照
してください。高品質なシステムについての国際標準については、ISO 9000 や
ISO 9001 [ISO 9000, 9001] を参照してください。  

この文書では、ある特定の環境にあるシステムやネットワークを安全に設定す
る方法については論じません。安全な設定は、あるプログラムを安全に使用す
るのに必須であることは明らかですが、安全に設定することを論じたドキュメ
ントは他にもたくさんあります。 Unix ライクなシステムを安全に設定するこ
とについて述べてある書籍には Garfinkel [1996]という素晴らしい作品があり
ます。他にも、Anonymous[1998]というものがあります。また Web サイトでも
情報を得られます。たとえば http://www.unixtools.com/security.html 等で
す。 Linux システムを安全に設定する情報については、さまざまなドキュメン
トが利用可能です。Fenzi[1999] や Seifried[1999]、Wreski[1998]、Swan
[2001]、 Anonymous[1999] がそれに当たります。 Geodsoft [2001] では
OpenBSD をいかに強固にするかといったことに加えて、 Unix ライクなシステ
ムに役に立つ示唆がたくさんあります。 Linux システム(つまるところ他の
Unix ライクなシステムも)をターゲットにしているなら、Bastille Hardening
Systemを調べるのも良いでしょう。このシステムは Linux オペレーティングシ
ステムをより強固で厳重にしようとしています。さらに Bastille について知
りたいなら、 http://www.bastille-linux.org を見てください。General
Public License (GPL) にしたがって自由に利用できます。 Windows 2000 がタ
ーゲットなら Cox[2000] を見るのもよいでしょう。米国国家安全保障局(The
U.S. National Security Agency(NSA)) は、セキュリティに関しての推奨ガイ
ドを http://nsa1.www.conxion.com で整備しています。その中には、「60
Minute Network Security Guide」というものもあります。

コンピュータを設定するのは、セキュリティ管理の一部にしかすぎません。セ
キュリティ管理は広範な内容をカバーしています。ウイルスへの対処方法やど
のような組織的なセキュリティ・ポリシが必要で、事業継続計画はどうするの
か、といったこと等を含んでいます。セキュリティ管理には国際的な基準とガ
イドラインがあります。 ISO 13335 は全 5 部からなるテクニカル・レポート
から構成され、セキュリティ管理の手引きになっています[ISO 13335]。また
ISO/IEC 17799:2000 では作業標準を定義しています[ISO 17799]。規定した目
的は、「組織にあって、セキュリティ管理を企画、実行し、それを維持する責
任を負う立場の人間に推奨する情報を提供する」ことです(幅広い内容を扱って
います。技術文書ではありません)。興味深いのは ISO/IEC 17799:2000 の意見
が分かれているところです。ベルギーやカナダ、フランス、ドイツ、イタリア
、日本、米国は採択に反対しました。議論についての詳細は、NIST(National
Institute of Standards and Technology) の ISO/IEC 17799:2000 FAQ <http:
//csrc.nist.gov/publications/secpubs/otherpubs/reviso-faq.pdf> を見てく
ださい。 The Commonly Accepted Security Practices & Recommendations
(CASPR)( http://www.caspr.org)プロジェクトは、セキュリティ情報を集約し
、誰もが利用できるドキュメントの作成に取り組んでいます (誰もが将来の文
書の派生物を入手可能であり続けられるように、GNU FDL ライセンスとしまし
た)。

この文書は読者の方がコンピュータのセキュリティ一般や、Unix ライクなシス
テム、ネットワーク(特に TCP/IP ベース)、C 言語について理解していること
を前提にしています。この文書には Linux や Unix でセキュリティを維持する
のに必要なプログラミング・モデルの情報があります。 TCP/IP ベースのネッ
トワークや安全なプロトコルを含むプロトコルの動作についてさらに知りたい
なら、[Murhammer 1998] のような TCP/IP 全般についての資料を調べてくださ
い。

この文書は Unix ライクなシステムを全て網羅しています。Linux をはじめ、
さまざまな系列の Unix を含んでいますが、特に Linux に焦点を当て、Linux
に特化した情報を提供します。 Windows CE に焦点を当てたところもあります
が、実際大部分の項目は特定のオペレーティングシステムに限定されません。
関連した情報でここで触れていない事項があれば、お知らせください。

この文書の原本は、http://www.dwheeler.com/secure-programs にあります。
この文書は Linux Documentation Project (LDP) http://www.linuxdoc.org の
一部でもあり、ミラーサイトがいくつか存在しています。ミラーにある LDP の
コピーやディストリビューションにあるものは、原本よりも古いかもしれない
ので注意してください。この文書について意見がいただけると助かりますが、
最新版をまず確認してから、送ってください。

This book is copyright (C) 1999-2001 David A. Wheeler and is covered by
the GNU Free Documentation License (GFDL); 詳しくは、Appendix C や 
Appendix D を見てください。

Chapter 2 それでは Unix や Linux、セキュリティの背景について論じます。 
Chapter 3 まず Unix と Linux のセキュリティ・モデル全般について論じてい
ます。そのモデルは、セキュリティに関する属性とプロセスやファイルシステ
ム等の操作について概観します。そして、この文書の要となる Linux と Unix
システム上でアプリケーション開発をするに当たっての、設計と実装のガイド
ラインが続きます。この文章は結論 Chapter 11 で締めくくり、その後に参考
文献一覧と付録がずらっと並びます。

プログラマの観点として重要と考える側面から、設計と実装についてのガイド
ラインを分類します。プログラムは入力を受取り、データを処理し、他のリソ
ースを呼び出し、出力を生成します。Figure 1-1はこれを図で表わしています
。つまり概念上、セキュリティ・ガイドラインはすべてこれらのカテゴリのど
れかに当てはまります。さらに「データ処理」を専門的な話題に分類します。
その分野とは、プログラム内部の構造化への取り組み方(Chapter 6)、バッファ
オーバーフロー(入力の問題として検討するケースもあります)の回避、言語に
固有の情報です。章の構成は、順序立てて理解しやすいようにしています。以
上の考えにもとづき、このガイドラインの章立ては次のようになります。入力
されるものすべてを検証する(Chapter 4)、バッファオーバーフローの回避 (
Chapter 5)、プログラムのインタフェースと内部構成をきちんとすること(
Chapter 6)、他のリソースを利用する場合は慎重に(Chapter 7)、情報はえりす
ぐってフィードバックする (Chapter 8)、言語固有の問題 (Chapter 9)、そし
て最後にどのように乱数を得るかといった、専門的な話題(Chapter 10)を扱う
こととします。

Figure 1-1. プログラム概念図

[program]

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

Chapter 2. 背景

                                    命じて調べさせたところ、その都は昔 
                                    から歴代の王に対して反抗し、反逆と 
                                    反乱を起こしたことが確認された。   
                                                                       
                                            旧約聖書エズラ記 4 章 19 節
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

2.1. Unix や Linux、オープンソースもしくはフリーソフトウェアについて

2.1.1. Unix

1969 から 1970 年にかけて、Kenneth Thompson 氏と Dennis Ritchie 氏らが
AT&T ベル研究所において、ほとんど使われていない PDP-7 上で、ちょっとし
たオペレーティングシステムを開発しはじめました。そのオペレーティングシ
ステムはまもなく Unix という洗礼名を授かりました。先に誕生した MULTICS
と呼ばれたオペレーティングシステムをもじって付けられました。 1972 から
1973 年にかけて、C 言語でシステムを書き換え、これによって思いがけない歴
史を歩むことになります。つまりこの決断によって Unix はオリジナルのハー
ドウェアから独立し、さらに生き長らえる最初のオペレーティングシステムと
なりました。 Unix には他にも新機軸の機能が加わりました。これはベル研究
所とアカデミックなコミュニティとの相乗効果のおかげでした。 1979 年に「
seventh edition」 (V7)と呼ばれるバージョンの Unix がリリースされ、現存
している Unix システムすべての始祖が誕生しました。 

この時点から Unix はいささか混迷期に入り込みます。アカデミックな世界で
は、バークレイ校がリーダーとなり Berkeley Software Distribution (BSD)と
言われる系列を開発しました。一方 AT&T は Unix を「System III」という名
で開発し続け、それが後に「System V」となりました。 1980 年の後半から
1990 年の前半にかけて、この 2 つのメジャーな系列間で「戦争」が勃発しま
した。その後何年もそれぞれの系列は、相手の重要な機能の多くを取り入れあ
いました。商用である System V が「標準化戦争」に打ち勝ち(そのインタフェ
ースのほとんどが公式の標準になりました)、ハードウェアベンダーの大部分が
AT&T の System V に移行しました。しかし、System V は BSD の革新的な技術
をたくさん組み込んでいて、結局は 2 つの支流を 1 つに統合したシステムと
なりました。 BSD 派は生き長らえ、研究分野や PC ハードウェア用、専用サー
バ(たとえば Web サイトは BSD の流れを汲むシステムを使っている場合が多
い)として広く利用されるようになりました。

こうして seventh edition を起源とする多彩なバージョンの Unix が存在する
結果になりました。 Unix の大部分のバージョンは、ハードウェアベンダーが
所有し、それぞれでメンテナンスをしています。たとえば Sun の Solaris は
System V 系列です。 BSD 系列の Unix の内 3 つのバージョンは、オープンソ
ースになりました。 FreeBSD(PC タイプのハードウェアに簡単にインストール
できることを目指す)や NetBSD(各種 CPU アーキテクチャ上で動作することを
目指す)、NetBSD の系列になる OpenBSD(セキュリティに重点を置く)がそれに
当たります。 Unix の歩みについてさらに詳細な情報は、 http://
www.datametrics.com/tech/unix/uxhistry/brf-hist.htm や http://
perso.wanadoo.fr/levenez/unix にあります。 BSD の歩みについてのさらに詳
しい情報は、 ftp://ftp.freebsd.org/pub/FreeBSD/FreeBSD-current/src/
share/misc/bsd-family-tree にあります。

少し前になりますが、短いのですが興味深い文書に John Kirch's paper
``Microsoft Windows NT Server 4.0 versus UNIX'' <http://web.archive.org
/web/20010801155417/www.unix-vs-nt.org/kirch> があります。これは Unix
ライクなシステムを使うことについて、論争を引き起こしました。【訳註：日
本語訳は、Microsoft Windows NT Server 4.0 と UNIX との比較 <http://
www.anc-tv.ne.jp/~peanuts1/Translation/kirch.net/unix-nt.j.html>にあり
ます】

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

2.1.2. Free Software Foundation

1984 年に Richard Stallman 氏の Free Software Foundation(FSF)はフリーな
Unix オペレーティングシステムを作り上げるために GNU プロジェクトを立ち
上げました。 Stallman 氏によればフリーとは自由に利用ができ、読むことが
でき、修正も可能で、再配布もできることを意味します。 FSF は膨大な数の役
に立つ OS の構成要素を開発しました。その中には C コンパイラ (gcc)や素晴
らしいテキスト・エディタ(emacs)他多数の基本的なツール類があります。しか
し、1990 年に FSF はオペレーティングシステムのカーネル開発で問題にぶち
当たりました[FSF 1998]。それはカーネルなしには残りのソフトウェアが動作
しないという問題です。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

2.1.3. Linux

1991 年に Linus Torvalds 氏はオペレーティングシステムのカーネルを開発し
はじめ、それに「Linux」という名前をつけました[Torvalds 1999]。このカー
ネルには FSF の成果物とその他の部分(BSD からいくつかと MIT の X Window
System)から構成され、自由に修正可能でかつ実践的なオペレーティングシステ
ムとなりました。この文書はカーネル自身を指す場合に「Linux カーネル」と
し、全体を組み合わせたものを「Linux」とします。よく使う「GNU/Linux」と
いう言葉は、この組み合わせを表す言葉と同じ意味で用いる場合が大半です。

Linux コミュニティでは、さまざまな組織がそれぞれ役に立つツールを組み合
わせています。それぞれの組み合わせは、「ディストリビューション」と呼ば
れ、ディストリビューションを開発する組織を「ディストリビュータ」と呼ん
でいます。よく知られたディストリビューションには、Red Hat や Mandrake、
SuSE、Caldera、 Corel、Debian があります。ディストリビューション間に違
いはありますが、同じコアを使ってディストリビューションを構築しています
。コアとは Linux カーネルと GNU glibc ライブラリを指します。両ソフトウ
ェアとも「copyleft」スタイルのライセンスになっていて、誰もがこのコア部
分の変更を利用できなければいけないことになっています。Linux ディストリ
ビューション間に存在するこの強制力は、BSD と AT&T から派生した Unix シ
ステムの間には存在していません。この文書では特定の Linux ディストリビュ
ーションをターゲットにはしません。 Linux について論ずる時には、前提とし
て Linux カーネルのバージョン 2.2 以上で、C ライブラリがバージョン 2.1
以上とします。現状のメジャーな Linux ディストリビューションはすべてこの
前提を満たしています。 

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

2.1.4. オープンソースとフリーソフトウェア

ソフトウェアを自由に共有することに対する関心が高まるにつれて、それを定
義し、説明することが必要不可欠になってきました。「オープンソース・ソフ
トウェア」という広く利用されている用語は[OSI 1999] でさらに詳しく定義し
てあります。 Eric Raymond[1997, 1998]は独創的な論文で、オープンソース・
ソフトウェアにおけるさまざまな開発プロセスについて説明しています。もう
1 つ広く使われている用語に「フリーソフトウェア」があり、ここで言う「フ
リー」とは「権利としての自由」を意味します。この例としてよく出されるの
は「言論の自由」であって「ただ酒」ではない、です。【訳註：free には、「
自由」と「無料」という 2 つの意味があります】。どちらの用語も完璧ではあ
りません。実行形式を無償で配布できたとしても、ソースコードを見られなか
ったり、修正できなかったり、再配布できなかったりしたものは「フリーソフ
トウェア」とは認めないのが通例です。逆に「オープンソース」という用語は
ソースコードは見られるが、利用や修正、再配布に制限があるソフトウェアを
意味する(非難する)場合に使われることがあります。さらに詳しい定義につい
ては Open Source Definition <http://www.opensource.org/osd.html> を見て
ください。この言葉を使う動機に違いがでる場合があります。「フリーソフト
ウェア」という言葉が好きな人は、「権利としての自由」が必要であることを
強調することを好みます。一方で、他の動機(たとえば信頼性が高いこと)を持
っていたり、それ程強硬に主張したいわけではなかったりする人が使っている
場合もあります。フリーソフトウェアについての定義や目的については http:/
/www.fsf.org を見てください。 

オープンソース・ソフトウェアやフリーソフトについての主張の数々に興味が
あるなら、http://www.opensource.org や http://www.fsf.org をぜひ見てく
ださい。その他にも Miller[1995]のようにオープンソース・ソフトウェアやフ
リーソフトについて調査した文書があります。その中でオープンソースは、企
業が所有しているソフトウェアよりもずば抜けて信頼性がある、となっていま
す(ソフトウェアに対してランダムな入力を行い、どれだけクラッシュに耐えう
るのか、独自に計測しています)。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

2.1.5. Linux と Unix を比較する

この文書では、「Unix ライクな」という言葉を、あえて Unix に似せたシステ
ムを指すために使っています。「Unix ライクな」という言葉は、メジャーな
Unix すべてと Linux ディストリビューションを指しています。「Unix」とい
う言葉を単に「Unix ライクな」と同じ意味で使っている人が多いことも忘れな
いでください。そもそも「Unix」は AT&T が開発した製品を意味します。今日
では Open Group が Unix の商標を所有していています。そこでは Unix を「
世界でただ 1 つの UNIX 規格」と定義しています。 

Linux は Unix のソースコードを受け継いでいませんが、インタフェースはあ
えて Unix に似せています。そのため、Unix の講義で学んだことはセキュリテ
ィの知識を含めてほとんどどちらのシステムにも当てはまります。この文書の
大半の情報はどんな Unix ライクなシステムにも当てはまります。 Linux を使
うとメリットが出る場合には、あえて Linux に特化した情報を追加しています
。

Unix ライクなシステムはいろいろとセキュリティの仕組みを共有していますが
、微妙に違いがあるので、すべてのシステムでその仕組みがすべて利用できる
わけではありません。プロセスに対するユーザやグループ ID(uid と gid)とフ
ァイルシステムに対する読み書き、実行権(ユーザやグループ、その他)はすべ
てのシステムで利用できます。 Thompson[1974]と Bach[1986]には Unix シス
テム一般についての情報があり、基本的なセキュリティの仕組みについても触
れています。 Chapter 3 では Unix と Linux のセキュリティ機能で鍵となる
ところを要約します。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

2.2. セキュリティの原則

セキュリティの原則として、当たり前に理解しておかなければならないことが
たくさんあります。 Information Assurance Technical Framework(IATF)[NSA
2000]は、広くセキュリティ情報を得るのに適したところです。 NIST は「原則
や手法として広く認められている」ハイレベルな場所と見られています。また
コンピュータのセキュリティを網羅しているテキストとして、[Pfleeger 1997]
等があります。ここで、セキュリティの原則についていくつか要約してみます
。

コンピュータセキュリティは全体で 3 つの目標があります。

 ・ 機密を保持する(秘密を保持するともいいます)。コンピュータシステム資
    産は認証を受けたメンバーだけがアクセスできることを意味します。
   
 ・ 完全な状態を保つ。認証過程を経て許可を受け、権限を持ったメンバーだ
    けが資産を変更できることを意味します。
   
 ・ 利用できること。権限を持ったメンバーが、資産へ適時(システムが必要と
    する要件によって決まる)アクセスできます。この目標が達成できない場合
    は、サービス拒否という状態になります。
   
さらに目標を追加する場合もありますし、追加した目標をこの 3 つの目標の特
殊なケースとしてまとめてしまうこともあります。たとえば、拒否しないこと
を独立した目標としている場合があります。これは、送り手側がメッセージを
送ったこと、受け手側がメッセージを受け取ったこと、またはその両方を「証
明」する能力のことです。たとえ、送り手側または受け手側が後でそれを否定
したくなったとしてもです。プライバシーを機密保持とは区別して扱う場合も
あります。データではなく、ユーザ(たとえばユーザの身元)の機密保持を守る
ことと定義する場合もあります。目標は、識別と認証を必要としている場合が
よくあり、時には独立した目標として記載してある場合もあります。監査(評価
とも言います)はセキュリティの目標として好ましいとされています。同様に「
アクセス制御」や「本人であることの認証」は別物として記載してある場合が
あります。どのケースであっても、プログラム全体に渡って、セキュリティの
目標と一致させることが重要です。目標をどのようにまとめようと、その目標
に合致することが重要なのです。

時にはこれらの目標が、既知の脅威に対する対抗手段である場合や法律で制定
してある場合もあります。たとえば、米国の銀行や金融機関に対して、「
Gramm-Leach-Bliley」(GLB)法というプライバシー関連の新しい法律ができまし
た。この法律では、共有される個人情報を開示すること及びそれらを安全にす
ることを必須とし、第三者との間で共有される個人情報の開示を要求し、さら
に、それらの機関に対して顧客がデータ共有を止めさせる機会を与えるよう指
導しています [Jones 2000]。

セキュリティとシステムやソフトウェア上のその他の技術方針とが相反する場
合があります。セキュリティが「簡単に使う」ことを妨げる場合があるからで
す。たとえば安全な設定を施すには、動作はするものの安全ではない設定より
も手間をかける必要があるかもしれません。この相反する点を解決できる場合
は多々あります。たとえば問題点をよく考えることで、簡単に利用ができてか
つ安全なシステムを構築できる場合がよくあります。セキュリティと抽象化(情
報の隠蔽)にも相反する点があります。たとえば高度なライブラリ・ルーチンは
、安全に実装してあろうがなかろうが、仕様からは何もわかりません。つまり
アプリケーションに安全が求められる場合、確信がもてないなら、自分自身で
実装しなければいけません。つまりそのライブラリを修正しなければいけない
ということです。あなたが不適切なライブラリ・ルーチンを選択すると、迷惑
を被るのはユーザなのです。

「徹底的に防御する」という原則は、セキュリティ上優れています。たくさん
の防御機構(階層)を適した場所に配置し、攻撃に成功するには複数の機構を攻
撃側が破らなければならないように設計します。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

2.3. なぜプログラマは危ないコードを書いてしまうのか

プログラマの多くは、危ないコードを書こうとしているわけではありませんが
、そうなってしまうのです。理由は山ほどあります。Bugtraq で Aleph One が
理由を集めて要約しています (1998 年 12 月 17 日に投稿されました)。

 ・ ほとんどの教育機関には、コンピュータのセキュリティを扱うカリキュラ
    ムがありません。カリキュラムがあったとしても、どのようにして安全な
    コードを書くのかは論じられていないのが普通です。カリキュラムの多く
    では、暗号法やプロトコルといった特定の分野だけしか学習できません。
    それらは確かに重要ですが、バッファオーバーフローや文字列のフォーマ
    ット、入力のチェックといった現実の世界で広く問題となっている点を論
    じるのを怠っています。これは最も重大な問題点の 1 つだと私は考えてい
    ます。大学を卒業したプログラマでさえ、安全なプログラムをどのように
    書いてよいのかについてまったく無知なのです。にもかかわらず、安全が
    必要となるプログラムを書くのでさえ、そのような人々が書いたプログラ
    ムに頼らざるえません。
   
 ・ プログラミングの書籍やクラスでは、安全で確実なプログラミング技術を
    習得できません。実際最近になるまで、安全にプログラムする方法につい
    ての書籍はまったくありませんでした(この文書は数少ないものの内の 1
    つです)。
   
 ・ 誰も正式な検証法を使っていません。
   
 ・ C 言語は安全な言語ではありません。標準 C ライブラリで用意してある文
    字列関係の関数も安全とはいえません。この点はとりわけ重大です。とい
    うのも C 言語は非常に広範に利用されていて、 C 言語を「深く考えず」
    に利用すると、危険なセキュリティホールを黙認することになります。
   
 ・ プログラマは「複数ユーザ」の扱いを考慮しません。
   
 ・ プログラマは人間で、人間は不精です。つまり、プログラマは安全なアプ
    ローチよりも「安直な」アプローチを取りがちです。つまり動作してしま
    えば、後から修正することはほとんどありません。
   
 ・ たいていのプログラマは優れているとはまったくいえません。
   
 ・ たいていのプログラマはセキュリティ関連の人間ではなく、攻撃側の考え
    にまで思慮が至りません。
   
 ・ セキュリティに関っている人間は、たいていプログラマではありません。
    これは Bugtraq への投稿者の何人かが主張していることで、真実であるか
    どうかははっきりしていません。
   
 ・ コンピュータのセキュリティ・モデルの大半はひどい代物です。
   
 ・ ソフトウェアの中には、既に「いかれてしまっている」のに使い続けられ
    ているものがたくさんあります。このソフトウェアを修正する(セキュリテ
    ィ上の問題を取り除き、より厳しいセキュリティ・ポリシの元で動かすよ
    うにする)のは困難です。
   
 ・ 消費者はセキュリティに無関心です。 (個人的には、消費者がセキュリテ
    ィに関心を持ちはじめることを望んでいます。いつもやられているコンピ
    ュータ・システムは、役に立たないどころか、使い勝手も良くありません
    。また消費者の多くは、問題があることにさえ気づいていないばかりか、
    状況が好転していないことすら知りません)。 
   
 ・ セキュリティを確保するには、余計な開発時間が必要になります。
   
 ・ セキュリティを確保するには、テストの面でも手間が増えます(仮想敵対チ
    ーム等)。
   
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

2.4. オープンソースはセキュリティに効果があるのか

セキュリティを実践している人間によって、オープンソースがセキュリティに
与える影響について、数多くの議論がなされてきました。主な論点の 1 つに、
オープンソースはソースコードを公開しているので、誰でもつまり攻撃側と防
御側のどちらもがソースコードを調べられるというものがあります。この状況
が決定的な影響力を持つことに、理性的な人びとは同意していません。

ここで、このトピックについて調査してきた方々を何人か紹介します。 Bruce
Schneier 氏は、「賢明な技術者なら、セキュリティに関連した事項はすべてオ
ープンソースのコードに求めた方が良い」[Schneier 1999]としています。また
オープンソースなソフトウェアを安全にするに必須の条件をいくつかを論じて
います。 Advanced Encryption Standard (AES)の暗号化アルゴリズムを勝ち取
った開発者である Vincent Rijmen 氏は、セキュリティ上の脆弱性を簡単に見
つけ出し、それを修正するのには Linux のオープンソースの特性がこの上ない
手段であると考えています。「より多くの人々が見るということ以上に重要な
のは、このモデルにおいて、より明快なコードを書くこと、標準を厳守するこ
とをみんなに強制している点です。これはセキュリティ・レビューをスムーズ
に繰り返し行うことに他なりません」 [Rijmen 2000] としています。 Elias
Levy (Aleph1) 氏は彼の論文である "Is Open Source Really More Secure
than Closed?" <http://www.securityfocus.com/commentary/19> でオープンソ
ースのソフトウェアを安全にする上での問題点を論じています。要約してみる
と下記のようになります。

   
    つまり、セキュリティ上の脆弱性が生じた時に、オープンソースとそうで
    ないソフトウェアは大差がないのでしょうか。それは違います。オープン
    ソースのソフトウェアはそうでないソフトウェアよりも、もっと安全にな
    る見込みが確かにあります。しかし勘違いしないで欲しいのは、単にオー
    プンソースだからといってセキュリティが保証されるわけでは無いという
    ことです。
   
John Viega 氏の論文である "The Myth of Open Source Security" <http://
dev-opensourceit.earthweb.com/news/000526_security.html> はこの点を論じ
ています。要約してみると下記のようになります。

   
    オープンソースのソフトウェア・プロジェクトは、そうでないプロジェク
    トのソフトウェアよりも安全になる力を秘めています。しかしオープンソ
    ースのプログラムが安全になるよりどころである、ソースコードが利用で
    きること、たくさんのユーザがセキュリティホールを見つけてそれを修正
    できるという事実は、人をだまして安心させることにもなり得ます。
   
Michael H. Warfield's "Musings on open source security" <http://
www.linuxworld.com/linuxworld/lw-1998-11/lw-11-ramparts.html> はさらに
確信を持って、オープンソースがセキュリティに対して影響力を持つことを主
張しています。 Fred Schneider 氏はオープンソースはセキュリティに役に立
つとは考えておらず、「多くの目が(オープンな)ソースに注がれることで、シ
ステムのセキュリティを危うくしてしまうバグを発見できると信ずるに足る理
由はありません」とし、また「コードに含まれているバグが、攻撃手法として
抜きんでているわけではありません」 [Schneider 2000]とも主張しています。
またオープンソースは、プログラム構築工程の管理を考慮していない、とも主
張していますが、実際には管理は存在しています。オープンソースのメジャー
なプログラムすべては、「責任者」の面目にかけて作成した公式バージョンが
いくつか存在します。 Peter G. Neumann 氏は「オープン・ボックス」ソフト
ウェア(ソースコードがある状況下でのみで恐らく利用可能)を論じていて、そ
の中で「オープン・ボックスであるソフトウェアはシステムのセキュリティを
本当に改善するのだろうか？自然とそうなるわけではない。ただ可能性は無視
できない」[Neumann 2000]としています。 TruSecure Corporation という Red
Hat(オープンソースで企業活動している)が資金提供をしている企業は、オープ
ンソースがなぜセキュリティに有効であると思われているのかを書籍にまとめ
ました[TruSecure 2001]。 Natalie Walker Whitlock's IBM DeveloperWorks
article <http://www-106.ibm.com/developerworks/linux/library/
l-oss.html?open&I=252,t=gr,p=SeclmpOS> では賛否両論を載せています。【訳
註：Natalie Walker Whitlock's IBM DeveloperWorks article の日本語訳は、
http://www-6.ibm.com/jp/developerworks/linux/010615/j_l-oss.html にあり
ます】。 Brian Witten 氏と Carl Landwehr 氏、Micahel Caloyannides 氏
[Witten 2001] は IEEE のソフトウェア関連論文でソースコードが利用できる
と、システムのセキュリティに好都合に物事が運ぶはず、と控えめに結論づけ
ています。彼らによると、

   
    「私たちは、この議論からさらに 4 つの結論を引き出せます。第一に、ソ
    ースコードにアクセスできれば、ユーザがシステムのセキュリティを改善
    できるようになります。そのような才能と人材があるならばですが。第二
    に、限られたテストでは一部のケースしか指摘できませんが、オープンソ
    ースのライフサイクルをもってすれば、悪意の無い欠点に対して、より脆
    弱さが少ないシステムを構築できます。第三に、3 つのオペレーティング
    システムを数年間調査したところ、12 か月に渡ってパッチが無い状態で既
    知の脆弱性をさらした日数が、2 つの商用システムよりも、残り 1 つのオ
    ープンシステムの方が短かかった、という結果になりました。最後になり
    ますが、行き詰まっているのはオープンではない商用システムの開発モデ
    ルの方です。システムとは手間をかけて維持、サポートして行くことでよ
    り安全になるということ、手間をかけないシステムは安全ではないが利益
    は上がる、という相反する問題であるからです。結論は出ているには出て
    いますが、この大切な点の議論はまだ中途半端で、消費者に提供されるセ
    キュリティを反映できる基準が切に望まれています」
   
注意して欲しいのは、時として脆弱性には、その存在を知られていないゆえに
やられない場合があることです。つまりそのようなシステムは「実質的には安
全」なのです。理屈上これは真実ですが、問題は誰かがその脆弱性を見つけ出
したなら、脆弱性の修正に貢献せずに悪用するかもしれないという点にありま
す。脆弱性が知られていないとしても、実際にその脆弱性がどこかに行ってし
まうわけではありません。ただ、その脆弱性が時限爆弾のようにいつ悪用され
るか知りようがないだけです。発見した脆弱性を誰かが悪用するという問題は
、システムがオープンソースであろうがなかろうが本来関係ありません。ソー
スコードの無いシステムは、より安全であるという主張がなされてきました。
攻撃側にとって情報が少ないため、脆弱性を見つけにくい、というのがその理
由です。それに相対するものとして、攻撃側はほとんどソースコードを必要と
しておらず、ソースコードを利用したいと思う時には逆アセンブルしてソース
コードを再生成してしまう、という意見があります。 Flake [2001]では、オー
プンでないコードに対してセキュリティ上の脆弱性をどのように調べているか
を論じています(たとえば、逆アセンブラを使って)。かたや防御側は、ソース
コードが無ければ問題を探しようがありません。防御側はソースコードが無い
と、攻撃側と比べて不利な立場になります。

脆弱性に対しての警告を発したり、脆弱性について議論したりしない方が良い
、という主張がなされる時もあります。この説は理屈上はもっともらしいので
すが、問題は攻撃側が既にありとあらゆる経路を通じて、脆弱性についての情
報を流してしまっているという点です。つまり、そのようなアプローチでは防
御側が脆弱なままで、攻撃側をまったく抑え込めません。これまで企業は、脆
弱性があからさまになるのを必死に隠し通そうとしてきました。しかし実績を
見てみると、おおかたの企業はユーザに広く知れ渡るまで脆弱性を修正しませ
んでした(脆弱性を修正したと主張できたのにもかからわず)。これは「全面開
示」が必要であることの論拠になっています。 Gartner グループは CNET.com
での記事「Commentary: Hype is the real issue - Tech News」で率直にコメ
ントしています。

   
    Microsoft の security response center のマネージャである Scott Culp
    氏は、情報について長年言い争われていることに対し、オウムのようにお
    決まりの文句を並べています。情報の配布についての道義的な議論は何度
    も繰り返され、既にお馴染みになっています。たとえば、数世紀前に教会
    はコペルニクスとガリレオの天動説を弾圧しようしましたが...。 Culp 氏
    は Microsoft の製品で最近続発している脆弱性について「情報セキュリテ
    ィの専門家」を非難しようとしていますが、これは単に不誠実なだけです
    。製品を製造した企業への批判を反らそうとする試みを象徴しているとも
    言えますが...。関係者すべてが本当に努力すべきことは、改善のプロセス
    を途切れなく行うことです。より広範に脆弱性が知られれば、より速やか
    に修正ができます。 
   
オープンソースのプログラムは、単独の企業が管理を強制していないため、誰
かがトロイの木馬や悪意あるコードを潜り込ませることができる、という主張
が時としてなされます。確かにトロイの木馬はオープンソースのコードに入れ
込むことは可能です。しかし同じように商用のコードにも潜り込ませられます
。従業員の中で、不満を抱えていたり、競争相手から賄賂を受けていたりして
いる者が、悪意あるコードを潜り込ませるかもしれません。また組織の多くで
は、オープンソースであるプログラムのように、問題を発見できそうにありま
せん。なにしろ組織外の人間は、誰もソースコードをレビューできないわけで
すし、社内でコードをレビューしている企業は、ごく少数に過ぎないからです
(レビューを行っていたとしても、レビューしたコードが実際に使用されるとい
う保証は、ほとんどありません)。オープンソースで無い企業を後で訴えられる
、という考えもほとんど根拠がないことに注意してください。ライセンスのほ
とんどすべては、押し並べて保証というものを放棄しており、裁判所は普通、
ソフトウェア開発会社に責任を負わせません。

Borland の InterBase サーバの件は、この点で興味深いケースです。 1992 か
ら 1994 年という長い間、Borland は故意に「バックドア」を「InterBase」と
いうデータベース・サーバにしかけていました。このバックドアは、ローカル
、リモート両ユーザがあらゆるデータベース・オブジェクトの操作ができ、任
意のプログラムをインストールできてしまい、場合によっては「root」として
そのマシンを制御できてしまうというものでした。この脆弱性は少なくとも 6
年もの間、製品に含まれたままでした。誰もこの製品をレビューできず、
Borland はその脆弱性を取り除くつもりもありませんでした。 Borland は
2000 年 7 月にソースコードを公開しました。「Firebird」プロジェクトがそ
のソースコードとともに立ち上がり、2000 年 12 月に InterBase のこの重大
なセキュリティ上の問題が露見しました。 2001 年 1 月に CERT はこのバック
ドアの存在を CERT advisory CA-2001-01 <http://www.cert.org/advisories/
CA-2001-01.html> として公表しました。あきれたことに、そのバックドアはプ
ログラムの ASCII ダンプ(クラッカーがよく使う手)をちょっと眺めただけで発
見できるようなものでした。この問題はオープンソースの開発者がコードをレ
ビューすることで発見され、すみやかにパッチが当てられました。パスワード
を知られなければプログラムは安全なままで、ソースを公開するとプログラム
が安全でなくなると主張されるかもしれません。私はそれは無意味だと考えま
す。ASCII ダンプは平凡で良く知られた攻撃手段の 1 つです。攻撃者すべてが
脆弱性を突然公開する衝動に駆られるわけではありませんし、実際のところ、
その脆弱性が何度にも渡って悪用されなかった、という確かな証拠はありませ
ん。はっきりしていることは、ソースが公開された後、ソースコードが何回も
レビューされ、脆弱性が見つかって修正された、ということだけです。この状
況をまとめると、オリジナルのコードに脆弱性があり、オープンソースになる
やいなや簡単にその脆弱性が発見され、最終的には修正されたということです
。 

ソースコードをオープンにする利点は、攻撃を受けるソフトウェアが増えない
ということではなく、脆弱性を走査し評価する機会が増えるということです。
脆弱性を走査し評価するには、設定済みのシステムで意図的に脆弱性を探し出
します。最近になって Network Computing evaluation は、最高の走査ツール
(数ある脆弱性の中でも最も悪質な脆弱性を発見した)は、オープンソースの走
査ツールである Nessus としました[Forristal 2001]。

いったい結論は何なのでしょう。個人的には、プログラムというものがまずオ
ープンソースとして作られると、最初はユーザにとって安全性が低くても(脆弱
性があらわになっても)、時を経るにしたがって(数年程度)、オープンでないプ
ログラムよりもさらに安全になる可能性があると考えています。プログラムを
ただオープンソースにするだけでは、すぐには安全になりませんし、オープン
ソースなプログラムにすることで、安全になる保証もありません。

 ・ まず実際にコードをレビューしなければいけません。これは議論において
    重要な点の 1 つです。現実的にオープンソースなプロジェクトであれば、
    コードはレビューされるのでしょうか。レビューを受ける回数が少なくな
    る要因はいろいろとあります。ニッチでほとんど利用されない製品(レビュ
    ーアの存在が期待できない)や開発者がほとんどいない場合、まれにしか使
    われないコンピュータ言語がそれにあたります。開発者が一人で協力者が
    いないプログラムは、間違いなくこの手のレビューを受けられません。そ
    の一方でプログラムの中には、中心となる作者が存在しかつ、ちょくちょ
    くコードを調べたり、他の人間が行ったレビュー(少なくとも貢献にはなっ
    ている)を提案したりするメンバーがたくさん関っている場合もあります。
    一般的にレビューアがたくさんいればいるほど、誰かが欠点を見つけ出す
    可能性がより高くなります。これは「たくさんの眼」理論の基本です。 
   
    オープンソースであること自体が、レビューを受ける見込みを著しく減ら
    す要因の 1 つになるわけではありません。ベンダーの中には「開示されて
    いるソース(disclosed source)」(「ソースが存在する」 (source
    available)とも言う)プログラムをオープンソースだとポーズをとるところ
    があります。しかしそのプログラムの所有者はあいかわらず広範囲に独占
    的な権利を有しているので、「無償で」所有者のために働こうという意欲
    がある人はほとんどいないでしょう。風変わりで変則的な権利形態をとる
    (MPL のような)オープンソースのライセンスでさえ、問題を抱えています
    。結局は、自分の成果に対して別の誰かが権利を持っているのであれば、
    ボランティアで参加する可能性は低くなるということです(Bruce Perens
    氏はこの点について、「一体誰が好んでただ働きで雇われの身になるんだ
    い？」と言っています)。やる気が旺盛なレビューアは、プログラムも修正
    したがります。このやる気を削ぐようなライセンスでは、たくさんの「眼
    」を失うことになります。 Elias Levy 氏はオープンソースのセキュリテ
    ィに関する彼の論文の中でこの点で間違いを犯しています。彼が分析した
    ソフトウェア(例えば TIS の Gauntlet)は当時オープンソースではなかっ
    たのです。
   
 ・ 第二に、コードを書いたり、少なくともレビューしたりする人の中に、安
    全なプログラムの書き方を理解している必要があります。できれば、この
    文書が役に立てばと願っています。「たくさんの眼」があっても、何を見
    つけだすかを知らなければ、何にもなりません。理解している人たちがい
    る限りは、みんながみんな安全なプログラムの書き方を知らなくてもかま
    わない、という点に気をつけてください。 
   
 ・ 第三に、一度問題が見つかったなら、すみやかに修正してそれを配布しな
    ければいけません。オープンソースのシステムでは、速やかに問題が修正
    される傾向にありますが、スムーズに配布されるとは限りません。たとえ
    ば、OpenBSD の開発者たちはセキュリティ上の欠陥をレビューするのに長
    けています。しかし、確認した問題点をオリジナルの開発者にいつもフィ
    ードバックするとは限りません。つまりあるシステムのあるバージョンを
    修正するのには都合が良いのですが、他のシステムは直されないままにな
    ってしまいます。
   
オープンソースのもう 1 つの長所は、問題をみつけたなら、あなたがそれをす
ぐに修正できるということです。

つまり、オープンソース・ソフトウェアのセキュリティへの影響度合いは、セ
キュリティ界でまだ広範囲に渡って議論している最中です。しかし、著名な専
門家の多くはより安全になる可能性が大であると考えています。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

2.5. 安全なプログラムの種類

安全にする必要があるプログラムは、多岐に渡ります(用語については、この文
書で定義します)。一般的な種類を下記にいくつかあげます。

 ・ 離れた所にあるデータを閲覧する場合に利用するアプリケーション・プロ
    グラム。ビューアーとして利用するプログラム(ワード・プロセッサやファ
    イル・フォーマットを見るためのビューアー)では、信頼できないユーザが
    、離れた場所から閲覧するデータを送るように求めることがよくあります
    (このリクエストは Web ブラウザが自動的に実行する可能性があります)。
    はっきりしていることは、信頼できないユーザの入力によって、アプリケ
    ーションが任意のプログラムを実行してしまってはいけない、ということ
    です。初期化マクロ (データを表示する時に実行する)をサポートするのは
    浅はかです。サポートせざるを得ないなら、必ず安全のためのサンドボッ
    クスを作成してください(サンドボックスを作る作業は複雑かつ間違いを起
    こしやすいので、うまくいくとは限りません。したがって、はなからマク
    ロをサポートするべきではないのです)。 Chapter 5 で議論するバッファ
    オーバーフローのような問題についても、注意が必要です。この問題は、
    信頼できないユーザがビューアーを使って、任意のプログラムを強制的に
    動かせるようにしてしまいます。【訳註：サンドボックス(sandbox)とは、
    制限付きで保護されたメモリ領域。この領域で動くアプリケーションは、
    システムにダメージを与えないように設計、動作します】
   
 ・ システム管理者(root)が使用するアプリケーション・プログラム。そのよ
    うなプログラムは、システム管理者以外が制御できてしまうデータを信頼
    すべきではありません。
   
 ・ ローカルでサービスを行うサーバ(デーモンとも呼びます)。
   
 ・ ネットワーク経由でアクセスするサーバ(ネットワーク・デーモンという場
    合もあります)。 
   
 ・ Web ベースのアプリケーション(CGI スクリプトもその一部)。これらのア
    プリケーションは、ネットワーク経由でアクセスするサーバとしては特殊
    なケースです。しかし、あまりにも普及しているので、これだけで一分野
    を作る価値があります。この分野に属するプログラムは、Web サーバを経
    由して間接的に実行され、フィルタされる攻撃も中にはありますが、防御
    すべきでありながら、多くはなすがままになっています。
   
 ・ アプレット(すなわち、クライアントにダウンロードされ、自動的に実行す
    るもの)。 Java がとりわけ有名ですが、他の言語(たとえば Python)も同
    様にモバイル・コードをサポートしています。ここにセキュリティ上重要
    な点がいくつかあります。それは、クライアント側でアプレットの実行機
    構を実装した人が、「安全な」オペレーションをだけを確実に実行するよ
    うにしているか、という点とアプレット作成者が、悪意のあるホストの問
    題(つまりクライアントは普通信頼できない)に対処しなければいけない点
    です。悪意のあるホスト上で、アプレットを問題なく動かす研究がいくつ
    かありますが、正直言って、この解決方法は疑問です。斬新なテーマなの
    で、ここではこれ以上触れません。【訳註：モバイル・コードは、クライ
    アントプログラム(たとえば Web ブラウザ) が相手のシステム(たとえば
    Web サーバ等)からダウンロードし、自動的に実行されるプログラム全般を
    指します】
   
 ・ setuid や setgid したプログラム。これらのプログラムは、ローカルにい
    るユーザが実行します。実行されるやいなやそのプログラムのオーナーも
    しくはオーナーのグループ(もしくはその両方)の権限が与えられます。い
    ろいろな意味で、これらは最も安全にしにくいプログラムです。それは入
    力の大部分が信頼できないユーザが制御していて、その入力自体も疑いが
    あるからです。 
   
 

この文書は、さまざまな種類のプログラムの課題をひとまとめにして扱ってい
ます。このやり方には欠点があります。それは、ここで扱う問題点には、プロ
グラム全種類へ適用できないものがある点です。特に setuid や setgid した
プログラムは、思いがけないさまざまな入力があり、ガイドラインには setuid
や setgid したプログラムだけに当てはまるものもあります。しかし、実際は
そんなに区別がはっきりしているわけではなく、あるプログラムではこの範疇
を越えるものもあります(たとえば CGI スクリプトは setuid や setgid され
たり、同じような影響がある方法で設定してあったりします)。また実行形式が
いくつにも分かれていて、そのそれぞれが異なる「種類」のプログラムになっ
ている場合もあります。さまざまな種類のプログラムをひとまとめにして検討
する利点は、あるカテゴリにプログラムを無理に当てはめることなく、問題を
包括的に検討できる点にあります。こうして見ていくことで、安全が求められ
るプログラムすべてに対して、原則が当てはまるケースが多いことがわかりま
す。

この文書は、C で書いたプログラムに多少偏っています。C++ や Perl、PHP、
Python、 Ada95、Java のような他の言語についても、多少は扱っています。こ
れは Unix ライクなシステムでは C が安全なプログラムを実装する言語として
最も普及しているためです(CGI は例外で、Perl や PHP、Python をよく使いま
す)。また C 以外の言語の大部分は、 C のライブラリを呼び出すように作られ
ています。これをもって C が安全なプログラムを作るという目的に「最良の」
言語である、ということにはなりません。ここで述べられる原則の大部分は、
使用している言語のいかんにかかわらず当てはまります。 

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

2.6. 疑い深く、こだわりが強いことに価値がある

安全なプログラムを書くのに当たって一番やっかいな点は、作成者が思考回路
を切り替えなければならないところにあります。つまり、疑い深く、こだわり
を強く持つ必要があることです。エラー(欠陥とかバグとも言われています)が
起こすシステムへの影響が、普通のプログラムとはまったく違うからです。

安全が必要とされていない普通のプログラムには、エラーがたくさんあります
。エラーは歓迎すべきものではありませんが、そう度々は起こらないのが普通
で、ありそうでありません。ユーザが万が一エラーに遭遇してしまっても、そ
のバグを何とか避けながら、利用し続けようとするでしょう。

安全が必要なプログラムではこの状況が一変します。とあるユーザは、意図的
にバグを捜し出し、ほとんど起こりそうもない状況を引き起こします。そして
、そのような攻撃で不当な権限を得ようとします。という訳で、安全なプログ
ラムを書く場合には、疑い深く、こだわりを強く持つことに価値がでるのです
。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

2.7. このドキュメントを書いた訳は ?

「どうしてこのドキュメントを書いたのか？」と質問を受けるのですが、私の
答えは下記の通りです。ここ数年来、Linux や Unix のデベロッパーは同じよ
うなセキュリティ上の落し穴に何度もはまりこんでいるように思えます。監査
する側は、問題をとらえるのが早いとは言えません。しかしバグが最初からコ
ードに入っていなかったなら、もっと良かったはずです。既知の落し穴にはま
らない方法について、ここさえ見れば、という共通の所がないところに問題の
一端があると考えています。情報は公開されているのですが、その情報を捜し
出すのが困難だったり、古くなっていたり、不十分だったり、別の問題を含ん
でいたりします。またそのような情報の大部分には Linux が広く利用されてい
るにもかかわらず、 Linux に焦点を当てた議論がまったくありません。このよ
うな背景から、ソフトウェアの開発者が過去の過ちを今後繰り返さず、システ
ムがより安全となることを願って、このドキュメントを書きました。この点に
ついてさらに知りたければ、http://www.linuxsecurity.com/feature_stories/
feature_story-6.html を参照してください。 

これと関連した質問に「他のドキュメントを参照するのに留めずに、どうして
自分自身でドキュメントを書いたのか？」というものもあります。答えはいく
つかあります。

 ・ 情報の多くは、あちこちに散在しています。重要な情報を体系的なドキュ
    メントにまとめれば、利用しやすくなります。
   
 ・ 情報の中にはプログラマ向けではなく、システム管理者やユーザ向けの情
    報もあります。
   
 ・ 入手可能な情報は、システム間で共通な要素(Unix ライクなシステムすべ
    てで動作する)に重点をおいている場合が多く、Linux についてはまったく
    論じられていません。移植性の点からすれば、Linux 固有の機能に触れる
    のを避けるのが確かに賢明です。しかし Linux に固有の機能を使えば、セ
    キュリティが確実に向上する場合があります。 Linux 以外への移植性が要
    求されても、Linux が動いていれば固有の機能を使いたくなるかもしれま
    せん。そして Linux を中心として、Linux を対象としている人々に役に立
    つ情報への参照を入れることがあります。その情報が他には必ずしも役立
    つとはいえないとしてもです。
   
 

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

2.8. 設計と実装の指針についての情報源

安全なプログラムを書く方法(あるいは、既存のプログラムのセキュリティ上の
問題点をどのように発見するのか)について、役立つドキュメントがいくつかあ
ります。またそれらのドキュメントは、このドキュメントでガイドラインとし
てこれから明確にしていく項目の根拠にもなっています。 

汎用的なサーバや setuid もしくは setgid したプログラムについては、役に
立つドキュメントがたくさんあります(ドキュメントの中には直接見つけるのが
困難なものがあります)。

Matt Bishop[1996, 1997] は、このトピックに関してたいへん素晴らしいドキ
ュメントを作成したり、発表を行ったりしています。その上彼の Web サイト 
http://olympus.cs.ucdavis.edu/~bishop/secprog.html でこのトピックを専門
に扱っています。 AUSCERT はプログラミングにあたってのチェックリスト 
[AUSCERT 1996] <ftp://ftp.auscert.org.au/pub/auscert/papers/
secure_programming_checklist> を公開しています。これは Garfinkel、
Spafford 両氏の著作 [Garfinkel 1996] <http://www.oreilly.com/catalog/
puis> の 23 章で論じている、安全な suid したネットワーク関連のプログラ
ム書法を下敷きにしています。 Galvin [1998a] <http://www.sunworld.com/
swol-04-1998/swol-04-security.html> は、安全なプログラムを開発する工程
やチェックリストについて分かりやすく説明しています。最近になってチェッ
クリストが更新され、 Galvin [1998b] <http://www.sunworld.com/
sunworldonline/swol-08-1998/swol-08-security.html> で見られます。 
Sitaker [1999] <http://www.pobox.com/~kragen/security-holes.html> には
、「Linux セキュリティ監査」チームが検討している問題について、その一覧
があります。 Shostack [1999] <http://www.homeport.org/~adam/
review.html> ではセキュリティに気を配る必要があるコードをレビューするの
に役立つチェックリストを定義しています。 NCSA [NCSA] <http://
www.ncsa.uiuc.edu/General/Grid/ACES/security/programming> では、安全な
プログラムのための簡潔かつ役に立つガイドラインを提供しています。その他
で情報源として役に立つのは、 Secure Unix Programming FAQ [Al-Herbish
1999] <http://www.whitefang.com/sup/> や Security-Audit's Frequently
Asked Questions [Graham 1999] <http://lsap.org/faq.txt>、 Ranum [1998]
<http://www.clark.net/pub/mjr/pubs/pdf/> があります。アドバイスの中には
注意しなければならないものがあります。例えば BSD の man の setuid(7) で
は [Unknown] <http://www.homeport.org/~adam/setuid.7.html>、 access(3)
の使用を推奨していますが、その使用にともなって生じる競合状態の危険さを
考慮していません。 Wood[1985]には、役に立つものの、古くなってしまったア
ドバイスが「Security for Programmers」の章にあります。 Bellovin [1994]
<http://www.research.att.com/~smb/talks> には役に立つガイドラインや
ftpd の実装をよりシンプルで安全に組み直すといったやり方の具体例がいくつ
かあります。 FreeBSD は FreeBSD [1999] <http://www.freebsd.org/security
/security.html> というガイドラインを用意しています。 [Quintero 1999]
<http://developer.gnome.org/doc/guides/programming-guidelines/
book1.html> は、そもそも GNOME のプログラミング・ガイドラインと関連があ
りますが、セクションの 1 つでセキュリティについて検討しています。 
[Venema 1996] <http://www.fish.com/security/murphy.html> は、安全なプロ
グラムを組む時にありがちなエラー(ありきたりなので推測可能なパスワードや
悪意あるデータによる汚染、ユーザがアクセスできるデータに含まれてしまっ
ている機密情報、他のプログラムへの依存)について詳しく (例を挙げて)論じ
ています。 [Sibert 1996] <http://www.fish.com/security/maldata.html> は
、悪意あるデータが引き起こす脅威について説明しています。

Web のインタフェースである Common Gateway Interface(CGI)は、プログラマ
向けドキュメントとして、セキュリティのガイドラインがたくさん用意してあ
ります。 Van Biesbrouck [1996] <http://www.csclub.uwaterloo.ca/u/
mlvanbie/cgisec>, Gundavaram [unknown] <http://language.perl.com/CPAN/
doc/FAQs/cgi/perl-cgi-faq.html>, [Garfinkle 1997] <http://webreview.com
/wr/pub/97/08/08/bookshelf> Kim [1996] <http://www.eekim.com/pubs/
cgibook>, Phillips [1995] <http://www.go2net.com/people/paulp/
cgi-security/safe-cgi.txt>, Stein [1999] <http://www.w3.org/Security/
Faq/www-security-faq.html>, [Peteanu 2000] <http://members.home.net/
razvan.peteanu>, and [Advosys 2000] <http://advosys.ca/tips/
web-security.html>.

ある特定の言語について触れたドキュメントはたくさんあります。このドキュ
メントでは、言語に固有な点に触れたセクションでさらに論じます。たとえば
、Perl の配布物の中には、 perlsec(1) <http://www.perl.com/pub/doc/
manual/html/pod/perlsec.html> というセクションがあり、Perl をより安全に
使う方法について論じています。 http://www.cs.princeton.edu/sip にある
Secure Internet Programming というサイトは、コンピュータのセキュリティ
全般について扱っていますが、Java や ActiveX、JavaScript といったモバイ
ル・コードの仕組みに焦点を当てています。 Ed Felten 氏(このサイトの中心
人物の 1 人)は Java を安全にする書籍を共著しています。 ([McGraw 1999]
<http://www.securingjava.com>)。この点については Section 9.6 で扱います
。 Sun が出しているコードを安全にするためのガイドラインには、主に Java
や C について触れたものがいくつかあります。 http://java.sun.com/
security/seccodeguide.html で利用できます。

Yoder[1998]には、アプリケーションのセキュリティに取り組む際に利用できる
パタンがいろいろあります。ガイドラインとしては具体性に欠けますが、日常
よく使うプログラミング・パタンとして役に立つと思います。 Schmoo グルー
プは、安全なコードを書く方法についての情報リンクを Web サイトに載せ続け
ています。http://www.shmoo.com/securecode。

別の側面から問題を論じているドキュメントも、たくさん存在します(たとえば
「システムをクラックするには」)。一例として McClure[1999]があげられます
し、インターネットという世界で見れば、さらに莫大な資料がころがっていま
す。また、あるコンピュータ・アーキテクチャを攻撃するにはどのように開発
すればよいか等についても、より広範囲なドキュメント(たとえば [LSD 2001]
のような) が存在しています。 Honeynet プロジェクトは、実際にどのように
攻撃を行っているのかについて、情報 (統計を含め)を集めています。 http://
project.honeynet.org を見れば詳細な情報が得られます。

既存のプログラムにおいて、脆弱性が既に確認されている情報も多量に出回っ
ています。この情報は、「そうしないようにする」という点では役に立ちます
。しかし、たくさんの具体的な例から、一般的に利用できるガイドラインを見
つけ出すのはかなり大変です。セキュリティについて議論するメーリングリス
トがあります。最も有名なものの 1 つに Bugtraq <http://SecurityFocus.com
/forums/bugtraq/faq.html> があります。このメーリングリストは脆弱性の一
覧を作成することに熱心に取り組んでいます。 CERT Coordination Center
(CERT/CC)は、代表的な機関の 1 つで、インターネット関連のセキュリティ上
の問題を報告しています。 CERT/CC はちょくちょく勧告を発行し、深刻なセキ
ュリティ上の問題やその影響度合いを解説し、パッチや善後策をどうやって得
たらよいのかを説明しています。詳しい情報は、 http://www.cert.org を見て
ください。ただし注意して欲しいのは、もともと CERT は小型コンピュータ緊
急対応チームであって、公式に「CERT」がセキュリティについての代表機関と
なっているわけではない点です。米国エネルギー省の機関である Computer
Incident Advisory Capability (CIAC) <http://ciac.llnl.gov/ciac> も脆弱
性について報告をあげています。それぞれのグループは同じような脆弱性を報
告していますが、ばらばらな呼び方をしています。この問題を解決するために
、MITRE は、「あきらかな脆弱さと起こる可能性がある脆弱さの共通化」
(Common Vulnerabilities and Exposures(CVE))の一覧を作成しています。この
一覧では、共通で一意に決まる識別子(name)を作って、一般的に広く知られて
いる脆弱性と誰かが発見したセキュリティ上の問題を載せています。 http://
www.cve.mitre.org を見てください。 NIST の ICAT はコンピュータの脆弱性
を検索可能な形でまとめたものです。CVE の脆弱性のカテゴリにもとづいてい
るので、後で検索や比較が可能になっています。 http://csrc.nist.gov/icat
を見てください。【訳註：MITRE と CVE の詳細は、 about MITRE <http://
www.mitre.org/about> と about CVE <http://cve.mitre.org/about/> を参照
してください】

このドキュメントは、私が最も有益かつ重要だと考えたガイドラインをまとめ
たものです。優秀なプログラマがこれを読んだだけで、かなり上手に安全なプ
ログラムを実装できるよう、下地を作ることを目標にしています。この目標を
単独でカバーできるドキュメントにはお目にかかったことはありませんが、こ
の取り組みは意義があると信じています。方針はバランスを取ることです。「
考えられるだけのガイドラインをリストアップする」(エンドレスな作業でいつ
までたっても形にならない)こと、「簡潔な」リストをいろいろあげてオンライ
ンで利用できれば、有益かつ簡潔にはなるものの、重大な問題が省略されてし
まうことが多く、この両者のバランスが大切です。はっきりしない場合は、手
引きを記載してあります。そういう場合は、誰もが「これさえ見ればすべて OK
」的なドキュメントを読んで、その情報を活用できるようになっている方が、
より効果的だと考えるからです。このドキュメントの構成(一覧はすべて、独自
でさまざまな構成になっています)は、私自身が作成し、ガイドライン(特にケ
イパビリティや fsuid のような Linux 独自のもの)の中にも、私自身が書いた
ものがあります。上記にあげた関連ドキュメントをすべて読むことを強くお薦
めします。しかし、それは現実的ではないですね。 

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

2.9. その他のセキュリティ情報源

セキュリティ問題に特化した Web サイトやメーリングリストは膨大な数が存在
しています。ここでは、その他のセキュリティ情報をいくつか挙げておきます
。

 ・ Securityfocus.com <http://www.securityfocus.com> は、一般的なセキュ
    リティ関連のニュースや情報を豊富に提供しており、セキュリティ関連の
    メーリングリストもたくさん主催しています。参加方法やアーカイブの見
    方については、Web サイトを見てください。 SecurityFocus で最も関連深
    いメーリングリストには、下記のようなものがあります。
   
     □ 上記で触れたように、「Bugtraq」メーリングリストは「コンピュータ
        のセキュリティ上の脆弱性についてのメーリングリストで、モデレー
        ターが存在しています。脆弱性が何であり、それがどのように攻撃を
        かけ、どうしたら防ぐことができるか、といったことについて、詳細
        な報告と議論をすべて公開しています」。
       
     □ 「secprog」メーリングリストは、モデレーターがいるメーリングリス
        トで、安全なソフトウェアを開発する方法論とテクニックを議論して
        います。私はこのメーリングリストをとても注目しています。モデレ
        ーターと連携して、 secprog で出た結論を取り入れ(結論に納得した
        場合)、このドキュメントに反映しています。
       
     □ vuln-dev メーリングリストは、潜在的にセキュリティホールとなるが
        、まだ穴を空けられていないものを議論しています。
       
 ・ IBM の「developerWorks: Security」は興味深い記事を集めています。 
    http://www.ibm.com/developer/security でさらに学習してください。【
    訳註：日本語サイト <http://www-6.ibm.com/jp/developerworks/>があり
    ます】
   
 ・ Linux 固有のセキュリティ情報を知りたいなら、 LinuxSecurity.com
    <http://www.linuxsecurity.com> がよいでしょう。 Linux のコードを監
    査することに興味があるなら、 Linux Security-Audit Project FAQ
    <http://www.linuxhelp.org/lsap.shtml> や Linux Kernel Auditing
    Project <http://www.lkap.org> も見てみるとよいでしょう。これらは、
    Linux のコードについてのセキュリティ上の問題に熱心に取り組んでいま
    す。
   
特定のシステムを安全にしようとしているなら、そのシステムのセキュリティ
関連のメーリングリストにももちろん参加してください(たとえば Microsoft
や Red Hat 等)。そうすれば、セキュリティのアップデート情報を得られます
。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

2.10. ドキュメントでの約束事

システムの man ページからの引用は、名称(番号)という形式にします。番号は
、 man のセクション番号です。「どこも参照していない」ポインタ値を NULL
とします。C コンパイラは、ポインタが必要なおおかたの環境で、整数の 0 を
NULL に変換しています。しかし、C の規格としては NULL が実際にすべてが 0
ビットで埋められるという実装を求めてはいません。 C と C++ は文字「\0
(ASCII の 0)」を特別扱いしています。この値をこのドキュメントでは NIL と
します(NIL は通常「NUL」としますが、「NUL」と「NULL」の発音が同じため)
。関数やメソッドの名前は、文脈によっては小文字ではじめる必要があったと
しても、常に大文字・小文字の使い分けは元のままにしています。「Unix ライ
クな」という用語を使う時には、Unix や Linux、そして Unix と非常に似通っ
た基本構造を持つその他のシステムを指します。 POSIX という言葉は使いませ
ん。というのは、Windows 2000 のように POSIX を部分的に実装はしていても
、まだセキュリティモデルがまったく異なっているものがあるからです。

攻撃者のことを「アタッカー」とか「クラッカー」とか「アドバーサリ(敵対
者)」と言います。ジャーナリストは「攻撃者」のかわりに「ハッカー」という
言葉を使う場合があります。このドキュメントではこの(間違った)表現を避け
ています。というのも、 Linux や Unix の開発者は、自身のことを「ハッカー
」としている場合が多いからです。この言葉は悪い意味で使われてはいません
でした。つまり、Linux や Unix の開発者にとって「ハッカー」という言葉は
、今でも専門家であり、コンピュータにとりわけ熱い思いを持っている人間を
意味しているのです。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

Chapter 3. Linux と Unix のセキュリティ機能

                                    慎重さがあなたを保ち、英知が守って 
                                    くれる                             
                                                                       
                                                旧約聖書箴言 2 章 11 節

Linux や Unix のセキュリティ機能のガイドラインについて論じる前に、プロ
グラマの立場から、その機能が何であるかを知っておいてもよいと思います。
このセクションでは、Unix ライクなシステムのほとんどで広く使われているこ
れらの機能をざっと説明します。しかし Unix ライクなシステム間にはかなり
ばらつきがあり、システムすべてがここで述べる機能を持っているわけではな
いことに注意してください。この章では、拡張機能のいくつかと Linux に固有
の機能についても注目して行きます。Linux のディストリビューション間の違
いは、セキュリティに関するプログラミングという点から見ると、ほとんど無
いといってもよいと思います。それは、基本的には同じカーネルと C ライブラ
リ(GPL ベースのライセンスは、技術革新を速やかに普及させます)。また、そ
れぞれの Unix の実装間にはセキュリティ関連での違いがいくつかありますが
、ここで説明することがすべてをカバーしているわけではありません。この章
では、たとえば強制アクセス制御(mandatory access control (MAC)) の実装の
ように、まだ Unix ライクなシステムの多くが実装していないものについては
議論しません。これから説明する機能が何であるか既に知っているなら、この
セクションを飛ばしても結構です。

プログラミングガイドは、Linux や Unix でのセキュリティ関連の一部を軽く
なぞるだけで、重要な情報は飛ばしてしまうケースが多く見られます。とりわ
け「どのように使うか」ということは大まかには論じますが、利用の際に関り
が出てくるセキュリティの属性については誤魔化しています。それとは逆に、
man には個々の関数について、詳細な情報が多量にあります。しかし man は個
々の関数をどのように利用するのか、という細かい説明でもって、セキュリテ
ィの問題を隠してしまっている場合があります。このセクションでは、そのギ
ャップを埋めるように心がけます。Linux でプログラマがよく利用しそうなセ
キュリティの仕組みについて概要を説明しますが、特にセキュリティによって
生じるやっかい事に焦点を当てます。このセクションは、普通のプログラミン
グ・ガイドよりもさらに突っ込んだ内容になっていて、セキュリティ関連の事
柄に焦点を絞り、さらに詳しい情報が得られるように参考文献をあげておきま
す。

まず基本的なところから。 Linux や Unix は 2 つの部分から構成されていま
す。それはカーネルと「ユーザ空間」です。プログラムのほとんどは、ユーザ
空間(カーネル上の)で動作しています。 Linux は「カーネル・モジュール」と
いう概念をサポートしていて、動的かつ簡単にコードをカーネルに追加できる
ようになっています。しかし依然としてカーネルは基本的な部分を内部に抱え
ています。他のシステムの中には(たとえば HURD のような)、「マイクロカー
ネル」ベースのシステムもあります。そのシステムは、機能をより限定した小
さなカーネルと従来はカーネルで実装していた低レベルの機能を「ユーザ」プ
ログラムとして実装しています。

Unix ライクなシステムには、大幅に改修を行って、米国国防省が要求している
MAC(B1 レベル以上)の強固なセキュリティに特別対応しているものがあります
。この版のドキュメントでは、これらのシステムやその課題は扱いません。そ
のうち範囲を広げて行きたいと思っています。さらに詳細な情報のいくつかは
、他のところで利用できます。たとえば、SGI の「Trusted IRIX/B」について
詳しいのは、NSA の Final Evaluation Reports (FERs) <http://
www.radium.ncsc.mil/tpep/library/fers/index.html> です。

ユーザがログインすると、そのユーザ名はユーザが属している uid(ユーザ ID)
や gid(グループ ID)を表す整数値に割り当てられます。 uid が 0 のユーザは
特別な権限(役割)を持っていて、「root」と言われてきました。 Unix ライク
なシステム(Unix も含む)のほとんどでは、root はセキュリティチェックのほ
とんどを受けることなく、システムを管理を行う場合に使用されてきました。
Unix システムの中には、gid が 0 のユーザも特別扱いになっていて、グルー
プレベルでリソースに対して無制限のアクセス権を持っているものもあります
[Gay 2000, 228]。この事は他のシステム(Linux のような)では当てはまりませ
んが、そのようなシステムであってもグループ 0 は、基本的にすべての権利を
持っています。というのも、システム関連の特別なファイルは、グループ 0 が
所有しているケースが多いからです。セキュリティの点から見て唯一「対象」
となるもの、それがプロセスです (いろいろなことを実行している正体がプロ
セスなのです)。プロセスはさまざまなデータにアクセスできます。ファイルシ
ステム(FSO)であったり、 System V のプロセス間通信(IPC)であったり、ネッ
トワーク・ポートであったりします。プロセスはシグナルを設定できます。そ
の他セキュリティ関連のトピックとしては、quota や limit、ライブラリ、監
査、 PAM があります。この後、サブセクションで詳しく見ていきます。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

3.1. プロセス

Unix ライクなシステムでは、ユーザレベルの動作はプロセスを動かすことで実
現しています。 Unix システムの大部分は「スレッド」をプロセスとは独立し
た概念としてサポートしています。スレッドはプロセス内でメモリを共有して
いて、システムのスケジューラはスレッド自身をスケジューリングしています
。 Linux はこれとは異なる方法で実行しています(私は優れたやり方だと思い
ます)。スレッドとプロセスは基本的に違いはありません。そのかわり Linux
においては、プロセスがもう 1 つのプロセスを起こした時に、どのリソースを
共有するのかを選択できます(たとえばメモリを共有するとか)。そして Linux
カーネルは、スレッドレベルで速度が最適になるように動作します。詳しい情
報は clone(2) を見てください。 Linux のカーネル開発者は「スレッド」や「
プロセス」というかわりに、「タスク」という言葉をよく使う点に注意してく
ださい。しかし、対外的なドキュメントには、プロセスという言葉を使います
(なので、ここではプロセスという言葉を使います)。マルチ・スレッドのアプ
リケーションをプログラムする場合には、上記のような違いを隠蔽するため、
通常は標準のスレッドのどれかを使った方が適切です。こうすると移植性が高
くなるだけでなく、ライブラリが間接的なレベルの機能追加を提供できます。
これは、複数のアプリケーションレベルのスレッドを、あたかもオペレーティ
ングシステムの単独のスレッドとして実行することで実現しています。こうす
ることで、あるシステムの何らかのアプリケーションは、性能がいくらか向上
できます。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

3.1.1. プロセスの属性

ここでは、Unix ライクなシステムで動くプロセスそれぞれが持っている代表的
な属性を挙げておきます。

 ・ ruid、rgid ――実 uid と実 gid のことで、この権限でプロセスが動いて
    います。
   
 ・ euid、egid ――実効 uid と実効 gid は権限のチェックに利用します(フ
    ァイルシステムを除く)。
   
 ・ suid、sgid ――保存 uid と保存 gid は下記で論じますが、権限の「有効
    化・無効化」をサポートするのに利用します。 Unix ライクなシステムの
    すべてがこの機能をサポートしているわけではありませんが、大半のシス
    テム(Linux や Solaris を含む)がサポートしています。システムがこの機
    能を POSIX 標準で実装しているかを調べたいなら、sysconf(2) を使って
    _POSIX_SAVED_IDS が有効か確かめてください。
   
 ・ 補助グループ――グループ(gid)の一覧で、ユーザがメンバーになっている
    グループの一覧です。オリジナルの version 7 Unix では、存在していま
    せん。プロセスは同時に複数のグループには属せず、特別なコマンドを使
    ってグループを変更しなければいけません。 BSD では、それぞれのプロセ
    スでのグループの一覧をサポートしており、より柔軟な構成をとっていま
    す。またこの追加機能は現在では広く実装されています (Linux や
    Solaris を含む)。
   
 ・ umask ――新しいファイルシステムの実体を作成する時に、デフォルトの
    アクセス制御の設定を決めるビット列です。umask(2)を見てください。
   
 ・ スケジューリング・パラメタ――プロセスにはそれぞれ、デフォルトのス
    ケジューリングのポリシがあります。SCHED_OTHER は、追加でパラメタを
    設定でき、 nice やプライオリティ、カウンターを設定できます。詳細は
    、 sched_setscheduler(2) を見てください。
   
 ・ limits ――プロセス単位のリソースの制限です(下記参照)。
   
 ・ ファイルシステムのルート――プロセスから見たルート・ファイルシステ
    ム("/")の位置。 chroot(2)を参照してください。
   
 

ここでは、プロセスに関連してはいるものの、あまり一般的ではないものを説
明します。

 ・ fsuid、fsgid ―― uid と gid はファイルシステムへのアクセス権限をチ
    ェックするのに使います。通常は、それぞれ euid や egid と同じです。
    この属性は Linux 独自です。
   
 ・ ケイパビリティ―― POSIX で定義しているケイパビリティ情報。プロセス
    についてのケイパビリティは、3 つあります。それは、実効、継承、許可
    です。POSIX ケイパビリティについての詳しい情報は、下記を見てくださ
    い。 Linux のカーネル 2.2 バージョン以上であればこの機能をサポート
    しています。他の Unix ライクなシステムでもサポートしていますが、一
    般的というわけではありません。
   
 

Linux において、どの属性が各々のプロセスに関連しているのかを正確に知る
必要があるなら、Linux のソースコードが最も信頼のおける情報源です。特に
、 /usr/include/linux/sched.h にある task_struct という定義は重要です。

新しいプロセスを起こすには、fork(2) システムコールを使うのが一般的です
。 BSD は vfork(2) という最適化をはかった改良版を導入しました。 vfork
(2) の基本的な考えは単純で、使う必要がなければ使わないです。詳しくは、
Section 7.6 を見てください。

Linux では、固有のシステムコールである clone(2)をサポートしています。こ
のシステムコールは fork(2) と同様に動作しますが、共有したいリソース (た
とえば、メモリやファイル・ディスクリプタ等)を指定できます。さまざまな
BSD システムでは rfork() システムコール(オリジナルは Plan9 で開発)を実
装しています。呼び出し方は異なりますが、基本的な考え方は同じです(これも
共有するものに対しての操作を強化して、プロセスを生成します)。プログラム
に移植性を持たせるなら、できればこれらのシステムコールをそのまま使うべ
きではありません。上記でも述べましたが、移植性を持たせるなら、それらの
システムコールを用いたスレッドライブラリをもとにした方が良いでしょう。

このドキュメントは、プログラムを書くための完璧なチュートリアルではあり
ません。したがって、プロセスを扱った一般的に利用できる情報については省
略しています。さらに情報として wait(2) や exit(2) といったドキュメント
も利用できます。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

3.1.2. POSIX ケイパビリティ

POSIX ケイパビリティはビットで値を構成し、普通 root が持っている権限を
分割し、より特化した権限を持つ大きな組み合わせとして再構成します。
POSIX ケイパビリティは、IEEE 標準のドラフトで定義されています。したがっ
て Linux 固有の機能でもありませんし、他の Unix ライクなシステムで広く採
用されてもいません。 Linux のカーネル 2.0 では POSIX ケイパビリティをサ
ポートしていませんが、 2.2 ではプロセスについて、POSIX ケイパビリティを
サポートしています。 Linux のドキュメント(このドキュメントも含め)の中で
、「root の権限が必要である」と書いてあった場合、「ケイパビリティが必要
である」とほぼ同じ意味になる、とケイパビリティについてのドキュメントに
述べられています。個々のケイパビリティについて知りたい場合は、ケイパビ
リティに関するドキュメントを読んでください。

Linux においては、ファイルシステム上にあるファイルに対してケイパビリテ
ィを適用することが最終目的です。しかし、これを書いている時点では、まだ
実装されていません。転送機能に対するケイパビリティはサポートされていま
すが、デフォルトでは無効になっています。Linux のカーネル 2.2.11 ではケ
イパビリティをより身近に利用しやすくする機能が加わりました。その機能は
「ケイパビリティ・バウンディング・セット(capability bounding set)」です
。ケイパビリティ・バウンディング・セットは、ケイパビリティのリストの 1
つで、システム上のどのプロセスもその管理下に入ります(さもなければ、特別
な init プロセスだけが管理します)。ケイパビリティがバウンディング・セッ
トになければ、権限がどれであってもプロセスから利用できません。この機能
を使っている例として、カーネルモジュールの読み込みを無効にする機能が挙
げられます。試験的ではありますが、この機能を駆使したツールに LCAP http:
//pweb.netcom.com/~spoon/lcap/ があります。【訳註：LCAP は、カーネルが
サポートしているケイパビリティを無効にすることによって、システムをより
安全にする仕組みです】

POSIX ケイパビリティについての詳しい情報は、 ftp://ftp.kernel.org/pub/
linux/libs/security/linux-privs で利用できます。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

3.1.3. プロセスの生成とその操作

プロセスは fork(2) やお薦めできない vfork(2)、Linux 独自の clone(2)を使
って生成します。これらのシステムコールはすべて、既存のプロセスを複製し
、2 つのプロセスを生成します。プロセスは execve(2)、もしくはそのフロン
トエンド(exec(3)や system(3)、popen(3) がその例)をコールして、別のプロ
グラムを実行できます。

setuid や setgid してあるプログラムを実行すると、プロセスの euid や
egid (それぞれ)には、そのファイルに設定してある値がセットされます。この
相関関係は、いにしえの Unix では競合状態を引き起こし、セキュリティ上の
弱点の源となっていました。以前は setuid や setgid してあるスクリプトに
対応していたからです。カーネルが、どのインタプリタが動作するのかを見る
ためにファイルをオープンする時と、(id がセットされ)インタプリタに制御を
返ってインタプリタがファイルを再オープンしてスクリプトを解釈する時の間
に、攻撃者がファイルを操ってしまう可能性がありました(直接にもしくはシン
ボリック・リンク経由で)。

Unix ライクなシステムは、setuid したスクリプトのセキュリティ上の問題に
対して、さまざまなやり方で対処してきました。あるシステムでは、実行スク
リプトに setuid や setgid のビットが立っていると、それを完全に無視して
います。Linux もこれに該当し、安全さは疑いようがありません。ごく最近の
System V R4 や BSD 4.4 のリリースでは、カーネルの競合状態を避けるために
、また違ったアプローチをとっています。これらのシステムでは、カーネルは
id がセットしてあるスクリプト名をインタプリタに渡す時に、パス名を渡さず
(これが競合状態を起こすことになります)、/dev/fd/3 というファイル名を渡
します。これはスペシャルファイルで、既にそのスクリプトでオープンしてい
ますので、攻撃者が悪用する競合状態は起こりえません。このようなシステム
においても、安全さが必要なプログラムに setuid や setgid してあるシェル
・スクリプト言語を使うのには賛成できません。理由は下記で論じます。

プロセスがさまざまな uid や gid の値に変化をもたらすケースも存在します
。 setuid(2) や seteuid(2)、setreuid(2)、Linux 独自の setfsuid(2)を見て
ください。特に保存ユーザ id(suid)という属性はそのケースに該当し、本当に
信頼されたプログラムが、一時的に uid を変更してしまいます。 Unix ライク
なシステムでは、suid を下記のルールの下でサポートしています。 ruid の変
更もしくは euid が ruid と異なる値になった場合は、suid には新しい euid
の値が設定されます。特権を持たないユーザは、自分の suid から自分の euid
を、ruid から euid を、 euid から ruid を設定できます。

Linux 独自の fsuid プロセス属性は、NFS サーバのようなプログラムで、ファ
イルシステムの権限に限って指定された uid に許可をあたえます。そのプロセ
スへシグナルを送る許可は与えません。 euid が変更されると fsuid は新しい
euid の値に変更されます。fsuid は setfsuid(2)という Linux 独自のシステ
ムコールを使って設定できます。 root 以外から呼び出された場合は、fsuid
には現在の ruid や euid、seuid、あるいは現在の fsuid しか設定できません
。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

3.2. ファイル

すべての Unix ライクなシステムは、「/」を情報が保存されている大元とし、
そこから広がる形でファイル木構造をつくっています。ファイル木構造はディ
レクトリを階層化していて、そのぞれぞれがファイルシステムのファイルシス
テム・オブジェクト(FSO)を持っています。

Linux においては、ファイルシステムのオブジェクト(FSO)には通常のファイル
やディレクトリ、シンボリックリンク、名前つきパイプ(ファーストイン・ファ
ーストアウトと言ったり、FIFO と言ったりします)、ソケット(下記を参照して
ください)、キャラクタスペシャル(デバイス)ファイル、ブロックスペシャル
(デバイス)ファイル等があります(Linux では find(1)コマンドにその一覧があ
ります)。その他の Unix ライクなシステムでもまったく同じ、もしくは似たよ
うな FSO の一覧があります。

ファイルシステム・オブジェクトは、ファイルシステム上に存在し、ファイル
木構造にあるディレクトリにマウントしたりアンマウントしたりします。ファ
イルシステムのタイプ(たとえば ext2 や FAT)とは、ディスク上にデータを配
置し、速度や信頼性等を最適化する、特定の約束事です。「ファイルシステム
」という用語をファイルシステムの種類と同じ意味で使う場合もよくあります
。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

3.2.1. ファイルシステム・オブジェクトの属性

ファイルシステムのアクセス制御の属性は多少変わっていて、アクセス制御は
マウント時に選択したオプションに左右されます。 Linux では、ext2 がファ
イルシステムとしては現状最も一般的ですが、おびただしい数のファイルシス
テムをサポートしています。たいていの Unix ライクなシステムも、複数のフ
ァイルシステムをサポートしています。Unix ライクなシステムは、それぞれで
複数のファイルシステムのタイプをサポートしています。

Unix ライクなシステムの多くは、少なくとも下記の情報を記録しています。

 ・ 所有 uid と gid ――ファイルシステム・オブジェクトの「所有者」を識
    別します。特に断りがない限り、普通は所有者もしくは root だけがアク
    セス制限に関する属性を変更できます。
   
 ・ 許可ビット――ユーザ(所有者)、グループ、その他ごとに、読み込み、書
    き込み、実行の権限を表すビット。通常のファイルの場合は、読み、書き
    、実行という文字通りの意味を持ちます。ディレクトリの場合、「読み込
    み」パーミッションはそのディレクトリの中を見られることを意味し、「
    実行」パーミッションは、別名「検索」パーミッションとも言われ、実際
    にそのディレクトリに入って、そこにあるものを使用できます。「書き込
    み」パーミッションは、そのディレクトリでファイルの追加、削除、変更
    ができます。追加だけを許可させたい場合は、下記に説明する sticky ビ
    ットを立てること。シンボリックリンクのパーミッションは、意味を持た
    ないことに注意してください。意味を持つのは、シンボリックリンクが存
    在しているディレクトリとリンク先のファイル自身のパーミッション値だ
    けです。
   
 ・ 「sticky ビット」――ディレクトリに設定されると、削除(移動)や名前の
    変更は、ファイルの所有者やディレクトリの所有者もしくは root しか行
    えなくなります。これは Unix 一般で利用されている拡張機能で、Open
    Group の Single Unix Specification version 2 に定めてあります。古い
    バージョンの Unix では「save program text」ビットと呼ばれ、メモリに
    常駐する(スワップアウトしない)実行形式ファイルであることを示してい
    ました。これが行えるシステムでは、root だけがこのビットを設定できる
    ようにしていました(そうしないと、ユーザが「すべて」をメモリに入れて
    しまうことで、システムをクラッシュできてしまいます)。 Linux では、
    このビットは通常のファイルに対して、何の影響も与えません。また一般
    ユーザでも、自分が所有するファイルに対して設定が可能です。 Linux が
    仮想メモリ管理を実装するにいたって、この機能はすたれてしまいました
    。
   
 ・ setuid、setgid ――実行形式ファイルに設定されると、実効 uid と gid
    にそのファイルの所有者 ID と gid が設定されます(各々独立に)。 Unix
    ライクなシステムは、この機能をすべてサポートしています。 Linux と
    System V では、setgid が実行権をまったく持たないファイルに設定され
    ると、そのファイルがアクセスされている時に、強制ロック(mandatory
    locking) がそのファイルにかかります(ただし、マウントしているファイ
    ルシステムが強制ロックをサポートしていれば)。この仕組みは負荷が非常
    に重く、Unix ライクなシステムで広く採用されてはいません。実際には、
    Open Group の Single Unix Specification version 2 の chmod(3)で、設
    定が無意味なら、システムは実行権がないファイルに対して setuid を有
    効にする要求を無視してもよいことになっています。 Linux や Solaris
    では、setgid がディレクトリに設定されると、そのディレクトリに作成さ
    れるファイルは、自動的にそのディレクトリの gid に設定し直されます。
    この方法で実現できるのが、「プロジェクト用ディレクトリの作成」です
    。特別に設定したディレクトリにユーザがファイルを保存すると、グルー
    プの所有者が自動的に変更されるようになります。しかし、ディレクトリ
    に setgid ビットを立てることは Single Unix Specification のような規
    格として規定されているわけではありません[Open Group 1997]。【訳註：
    ファイルのロック機能には、強制ロック(mandatory locking)とアドバイザ
    リ・ロック(advisory locking)があります。違いは、前者がカーネルがプ
    ロセスを監視しロック操作を行うので、プロセス間の依存関係を越えてロ
    ックが可能です。これに対して後者は、プロセス自身がロック操作を行う
    ので、そのプロセスの制御外のものに対してはロックが無効となります。
    詳しくは、カーネル付属のドキュメントの linux/Documentation/
    mandatory.txt を参照してください】 
   
 ・ タイムスタンプ――ファイルシステム・オブジェクトには、アクセスした
    り、修正したりした時間を記憶してあります。しかし、所有者は自由にこ
    れらの値を変更できるので(touch(1)を参照)、この情報を安易に信頼しな
    いようにしてください。 Unix ライクのシステムは、すべてこの機能をサ
    ポートしています。
   
 

下記は、ext2 ファイルシステムを使っている Linux 独自の属性になります。
しかし、同じ機能を持った他のファイルシステムもたくさんあります。

 ・ 変更不可(immutable)ビット――ファイルシステム・オブジェクトに対して
    、いかなる変更も認めません。 root だけが設定と解除ができます。この
    仕組みは、ext2 ファイルシステムだけがサポートしており、すべての
    Unix システム(場合によっては Linux ファイルシステムでも)で利用でき
    るわけではありません。
   
 ・ 追加限定(append-only)ビット――許可されるのは、ファイルシステム・オ
    ブジェクトの追加だけです。 root だけが設定と解除ができます。この仕
    組みは、ext2 ファイルシステムだけがサポートしており、すべての Unix
    システム(場合によっては Linux ファイルシステムでも)で利用できるわけ
    ではありません。
   
 

拡張機能で他に一般的なものは、「このファイルを消せない」ことを示すビッ
トです。

上記の値は、マウント時に適用される場合が多いので、あるビット値が既に値
(媒体上の値が何であれ)を持っていたかのように扱われる場合もあります。詳
しいことは mount(1)を参照してください。これらのビットは役に立ちますが、
注意する必要があります。それは平易で使いやすいこと、ある行為を防げるの
に十分なことです。たとえば、Linux においてはマウントする時に「noexec」
すると、そのファイルシステム上ではプログラムの実行ができなくなります。
man にも記述してある通り、これはそのシステムと互換性のないシステムで動
くバイナリがあるファイルシステムをマウントしようとする場合に使います。
Linux では、このオプションで誰かがファイルを実行することを完全には防ぎ
きれません。そのファイルをどこかにコピーし、そこで実行できてしまいます
し、「/lib/ld-linux.so.2」というコマンドを使って、そのファイルを直接実
行できてしまうからです。

ファイルシステムには、これらのアクセス制御に対するビット値をサポートし
ていないものもあります。繰り返しますが、mount(1)を見て、ファイルシステ
ムがどのように扱かわれるのか確認してください。とりわけ MS-DOS ディスク
は、Unix ライクなシステムでサポートされているケースが多く、デフォルトで
はほんのわずかな属性しかサポートされていません(またこれらの属性を定義す
るのは普通とはいえません)。その場合、Unix ライクなシステムは標準的な属
性をエミュレートします(おそらく特別なファイルをディスク上に置いて、実装
しています)。またそれらの属性は、普通 mount(1) コマンドで調整できます。

注意すべき重要な点は、ファイルを追加したり、削除したりするのに関係して
くるのが、そのファイルのパーミッションを表すビットとそのファイルがある
ディレクトリの所有者だけ、という点です。その Unix ライクなシステムが、
より高度な手法(POSIX ACL のような)を持っていれば話は別ですが。システム
に他の拡張機能がない場合(Linux 2.2 は普通は持っていません)はパーミッシ
ョンを表すビットに何もパーミッションが無いファイルは、ディレクトリに許
可があるなら削除できてしまいます。また、親ディレクトリが子ディレクトリ
にユーザやグループを変更できるようにしていると、そのディレクトリ配下の
ものはすべて、そのユーザとグループに置き換えが可能になります。

セキュリティに関して、IEEE の POSIX 規格では、ACL に関してのきちんとし
た技術を定義していて、ユーザやグループが持つパーミッションのリストをサ
ポートしています。ただ残念なことに、広くサポートされていないだけでなく
、Unix ライクなシステムであってもきちんと同じ方法でサポートされていませ
ん。たとえば、普通の Linux 2.2はファイルシステムに ACL はおろか、POSIX
ケイパビリティの値すら持っていません。

Linux で注目に値するのは、デフォルトでは root ユーザに対して ext2 ファ
イルシステムの領域をほんのわずかしか割り当てない点です。これは、不完全
ではありますがサービス拒否攻撃に対して防御になります。あるユーザが root
ユーザと共有しているディスクを一杯にしたとしても、root ユーザには使い残
しでちょっとした領域が残ります(たとえば重要な機能のためにとっておけま
す)。デフォルトでは、ファイルシステム領域の 5% が確保されています。
mke2fs(8) の「-m」オプションをよく見てください。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

3.2.2. 作成日時の初期値

作成日時には、下記のルールを適用しています。 Unix システムでは、新しい
ファイルシステム・オブジェクトが creat(2) や open(2) で作成されると、
uid にはそのプロセスの euid が設定され、gid にはそのプロセスの egid が
設定されるケースが多くあります。 Linux では fsuid という拡張機能がある
分、少々異なっています。 uid にはそのプロセスの fsuid が、gid にはその
プロセスの fsguid が設定されます。ディレクトリに setgid ビットが立って
いるか、そのファイルシステムの grpid が立っていれば、gid はそのディレク
トリの gid が実際には設定されます。ディレクトリに setgid する拡張機能は
、Sun Solaris や Linux を含む多くのシステムでサポートしています。先に書
きましたが、「プロジェクト」ディレクトリ(ある「プロジェクト」用のディレ
クトリ)では、そのプロジェクト用に特別にグループを作成します。ディレクト
リはそのグループが所有者で setgid してあります。そこにファイルを置くと
、自動的にプロジェクトが所有することになります。同様に、setgid ビットが
立っているディレクトリ中に新しいサブディレクトリを作成すると(ファイルシ
ステムの grpid も設定していない)、新しいサブディレクトリにもその setgid
ビットが設定されます(つまりプロジェクト用のサブディレクトリにも好都合で
す)。これ以外のケースでは、setgid は新しく作成したファイルに対しては普
通に振る舞います。「ユーザプライベートグループ」という仕組みの理論的な
根拠がここにあります(Red Hat Linux 他で使われています)。この仕組みにお
いては、メンバーそれぞれは自分たちだけで構成している「プライベート」グ
ループに属していて、デフォルトではそのグループにどのファイルの読み書き
も可能としています(グループに属しているのは自分たちだけなので)。このよ
うに、ファイルのグループ構成メンバーが継承されると、読み書きの権限も継
承されるわけです。【訳註：ユーザプライベートグループについては、この説
明だけではわかり難いので、ユーザプライベートグループ <http://
www.jp.redhat.com/manual/Doc71/RHDOCS/rhl-rg-ja-7.1/
s1-users-groups-private-groups.html> も参照してみてください】基本的なフ
ァイルシステム・オブジェクトのアクセス制御の値(読み書き、実行)は、 (要
求された値 & ~ プロセスの umask)から割り出します。新しいファイルでは、
sticky ビットも setuid ビットも常に立っていません。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

3.2.3. アクセス制御属性の変更

chmod(2)や fchmod(2)、chmod(1) を使って変更できますが、chown(1)や chgrp
(1) も見てください。 Linux では、Linux 独自の属性を chattr(1)で操作でき
るものもあります。

Linux で注意する点は、root だけしかファイルの所有者を変更できない点です
。 Unix ライクなシステムには、一般ユーザでも他のユーザにファイルの所有
権を移動できてしまうものもあります。これは混乱を招くもとなので、Linux
では許していません。たとえば、ディスク使用量の制限をかけたい場合にその
ような操作ができてしまうと、大きなファイルは他の人(犠牲者)のせいだ、と
いう言い訳を許してしまうことになります。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

3.2.4. アクセス制御属性を使用する

Linux や他の Unix ライクなシステムの大半では、読み書きの属性値はファイ
ルをオープンした時にだけチェックされます。つまりその後に読み書きしても
、再チェックは行われません。しかし、ファイルシステムは Unix ライクなシ
ステムの根幹なので、システムコールを何度も呼び出すことで、これらの属性
をチェックしています。これらの属性をチェックするシステムコールには、
open(2)や creat(2)、link(2)、 unlink(2)、rename(2)、mknod(2)、symlink
(2)、socket(2) があります。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

3.2.5. ファイルシステムの階層

長年の慣例で、「何のファイルはどこに置く」という約束事があります。出来
るだけきまりを守って、ディレクトリ階層の中に情報を格納してください。た
とえば、全体に関連する設定情報は /etc に置いてください。 Filesystem
Hierarchy Standard (FHS)は、この慣例を論理的に定義しようとしており、
Linux システムは広く採用しています。 FHS は従来の Linux Filesystem
Structure standard (FSSTND)をアップデートしたもので、Linux や BSD、
System V から知恵を拝借しています。 http://www.pathname.com/fhs に FHS
の情報がありますから、ご覧ください。概略については Linux では hier(5)を
、Solaris では hier(7)を参照してください。慣例は時には一致しない場合が
ありますが、コンパイルやインストール時に可能な限り融通が効くようにして
おいてください。

Linux Standard Base <http://www.linuxbase.org> が、FHS を採用したことに
触れておきます。この組織は Linux ディストリビューション間の互換性を高め
、準拠した Linux システムならどんなソフトウェアでも動作するように規格を
作り、それを促進する機関です。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

3.3. System V IPC

Linux や System V を含む Unix ライクなシステムの多くは、System V のプロ
セス間通信(IPC)をサポートしています。事実、System V IPC は Open Group
の Single UNIX Specification Version 2 で必須になっています[Open Group
1997]。 System V の IPC は 3 つのものから構成されています。メッセージ・
キュー、セマフォ、共有メモリがそれです。それぞれの属性は下記の通りです
。

 ・ 作成者や作成者が属するグループ、その他の者の読み書きのパーミッショ
    ン。
   
 ・ 作成者 uid と gid ――作成者の uid と gid。
   
 ・ 所有者 uid と gid ――所有者の uid と gid(初期状態では作成者の uid
    と同じ)。
   
 

下記のルールにもとづいてアクセスします。

 ・ プロセスが root の権限を持っていれば、アクセスは許可されます。
   
 ・ プロセスの euid が所有者もしくは作成者の uid と同じなら、作成者のパ
    ーミッションを見て、問題なければアクセスが許可されます。
   
 ・ プロセスの euid が所有者もしくは作成者の gid と同じ、もしくはプロセ
    スの属するグループの中に所有者もしくは作成者の gid と同じものがあれ
    ば、作成者のパーミッションを見て、問題なければアクセスが許可されま
    す。
   
 ・ 以上に当てはまらなければ、「その他のユーザ」のパーミッションをチェ
    ックします。
   
 

root もしくは所有者や作成者の euid を持つプロセスは、所有者の uid や
gid を設定でき、また削除も可能であることを忘れないでください。詳しくは
ipc(5)を参照してください。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

3.4. ソケットとネットワーク接続

ソケットは情報を伝える手段として、特にネットワーク越しの通信に使用され
ています。ソケットは、そもそも Unix システムの流れの 1 つである BSD 系
が開発しました。しかし他の Unix ライクなシステムに対しても、およそ移植
しやすくなっています。 Linux や System V 系はソケットを BSD と同レベル
でサポートしており、Open Group の Single Unix Specification [Open Group
1997]でも必須とされています。以前 System V システムでは、ネットワーク越
しの通信インタフェースを別に持っていました(互換性がありませんでした)が
、Solaris のようなシステムもソケットをサポートしているのは注目に値しま
す。 socket(2)は情報を伝えるための接続ポイントを作成し、それを示すディ
スクリプタを返します。これはファイルに対する open(2)とある意味同じです
。ソケットのパラメタには、プロトコル・ファミリーとタイプを指定します。
つまりインターネット・ドメイン(TCP/IP version 4)や Novell の IPX もしく
は「Unix ドメイン」というように。サーバは、通常は bind(2)を呼んでから
listen(2)を呼び、accept(2) もしくは select(2)します。クライアントはとい
うと、bind(2)(省略される場合あり)を呼び、connect(2)します。詳しい情報は
それぞれの man を参照してください。ソケットを利用するのに man だけでは
難しいかもしれません。 Hall "Beej" [1999]のような資料を読んで、どうやっ
てこれらのシステムコールを組み合わせて利用するのかを学ぶのもよいと思い
ます。

「Unix ドメイン・ソケット」はネットワーク・プロトコルに実際は該当しませ
ん。というのは、同一マシン上で接続するに過ぎないからです。 (このドキュ
メントを書いている時点の標準的な Linux カーネルでは) ストリームとしてこ
のソケットを使う場合、名前つきパイプと非常に似てはいますが、際だった長
所があります。 Unix ドメイン・ソケットがコネクション指向である点に注目
してください。ソケットに対する新しい接続は、それぞれ新しい接続チャネル
となります。この点が名前つきパイプとは大きく異なる点です。この特性によ
って、Unix ドメイン・ソケットは、名前つきパイプの代わりに使われ、IPC を
実装し、重要なサービスを広く提供しています。名前なしパイプもそうなので
すが、socketpair(2)を使って、名前なしの Unix ドメイン・ソケットも使えま
す。名前なし Unix ドメイン・ソケットは、名前なしパイプとある程度似てい
るので、IPC に使えます。

Unix ドメイン・ソケットには、セキュリティに関する興味深い点がいくつかあ
ります。まず、Unix ドメイン・ソケットはファイルシステム上に存在するよう
に見え、stat(2) も利用できますが、open(2)では開けません(socket(2)とその
仲間のインタフェースを使わなければいけません)。次に、Unix ドメイン・ソ
ケットはファイル・ディスクリプタでプロセス間をやりとりします(ファイルの
中身ではなく)。この変わった機能は、これまで色々な場面で使われてきました
。他の IPC の手段では、この機能を利用できません(ディスクリプタは、そも
そもコンピュータ・サイエンスの言葉で言う「ケイパビリティ」の制限版とし
て利用できます)。ファイルディスクリプタを sendmsg(2)を使って送り、そこ
にある msg(メッセージ) フィールドに当たる msg_control が control
message のヘッダ配列を指し示しています(msg_controllen フィールドは配列
が何バイトあるのかを指定していなければいけません)。 control message は
cmsghdr 構造体になっていて、制御データの後に実データが続いています。こ
の目的に使うなら、cmsg_type に SCM_RIGHTS を設定してください。ファイル
ディスクリプタは recvmsg(2) を使って取り出し、後は似たような方法でデー
タに行き着きます。正直いうと、この機能はとても奇をてらった方法ですが、
知っておいても無駄ではありません。

Linux 2.2 以降で Unix ドメイン・ソケットにさらに機能が追加されています
。それは相手側の「認証」ができる点です(pid や uid、gid を利用可能)。サ
ンプルコードは下記のようになります。

 /* fd= file descriptor of Unix domain socket connected                
    to the client you wish to identify */                              
                                                                       
 struct ucred cr;                                                      
 int cl=sizeof(cr);                                                    
                                                                       
 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &cl)==0) {           
   printf("Peer's pid=%d, uid=%d, gid=%d\n",                           
           cr.pid, cr.uid, cr.gid);                                    

標準的な Unix での慣例では、TCP や UDP のローカルなポート番号は 1024 よ
り小さく、root の権限が必要になります。一方プロセスは 1024 以上のポート
であれば、制限無しにつなげられます。 Linux はこの慣例を踏襲していて、さ
らにプロセスは CAP_NET_BIND_SERVICE というケイパビリティが必要となり、
これで 1024 以下のポート番号に接続できます。通常このケイパビリティは、
euid が 0 であるプロセスだけが持つことができます。冒険好きな人なら、
Linux のソースを調べればわかります。 Linux 2.2.12 なら /usr/src/linux/
net/ipv4/af_inet.c にある関数の inet_bind()がそれです。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

3.5. シグナル

シグナルは、Unix ライクな OS 世界における単純な「割り込み」方式で、
Unix では古くからある機能の 1 つです。プロセスは、「シグナル」を別のプ
ロセスに送れ(たとえば kill(1)や kill(2) を使って)、その相手のプロセスは
それを受取り、非同期にそのシグナルを扱います。プロセスが他のプロセスに
任意のシグナルを送るには、送り手のプロセスが root もしくは、相手のプロ
セスの実もしくは実効ユーザ id の権限を持っていなければいけません。しか
し、シグナルを別の方法で送ることもできます。特に SIGURG はネットワーク
越しに TCP/IP のアウト・オブ・バンド(out-of-band (OOB))メッセージを使っ
て送れます。【訳註：「アウト・オブ・バンド」とは、データとは独立の通信
経路を使って、制御用情報を交換することです】

シグナルはいにしえからの Unix の機能の 1 つですが、実装も書き方もさまざ
まです。「シグナルを処理している時に、他のシグナルが発生したらどうなる
か？」という根本的な問題を抱えています。 libc5 を採用している古い Linux
ではシグナルのいくつかで操作方法が最新の GNU libc ライブラリと異なる点
があります。シグナルハンドラで C ライブラリ関数を安全に呼び出せない場合
がよくあり、システムコールの中にさえ、安全でないものがあります。ドキュ
メントを確認して、シグナルから呼び出しても安全であることが保証されてい
るかを確認してください。詳しい情報は、glibc FAQ(ローカルに /usr/doc/
glibc-*/FAQ というコピーがあるシステムもあります)を見てください。

新しくプログラムを書くなら、POSIX シグナルシステム(BSD のものにかわっ
て) を使ってください。この仕組みは広くサポートされていて、古いシグナル
システムが持っていた問題のいくつかを解決しています。 POSIX シグナルシス
テムは、sigset_t というデータ型を使うことを前提にしていて、そのデータ型
を扱う関数によって操作できます。その関数は、 sigemptyset()と sigfillset
()、sigaddset()、sigdelset()、sigismember()です。 sigsetops(3)にこれら
の関数についての説明があります。設定したなら、sigaction(2)や
sigprocmask(2)、sigpending(2)、 sigsuspend(2)を使って、シグナルの操作を
設定してください(詳細な情報は man を見てください)。 

通常はシグナルハンドラをどれもできるだけ短くかつ単純にし、競合状態に注
意を向けてください。シグナルはそもそも非同期に発生するので、恐らく競合
状態が起こるでしょう。

サーバにはある共通した慣例があります。SIGHUP を受けた場合には、ログファ
イルをすべて閉じ、設定ファイルを再オープンして読み込み、再びログファイ
ルを開きます。これでサーバを止めず再設定が行え、データをなくすことなく
ログをローテーションできます。何らかのサーバを書いていて、この慣例をな
るほどと思うなら、ぜひこの機能をサポートしてください。

Michal Zalewski [2001] はどうやってシグナルハンドラが攻撃を受けるかにつ
いて、素晴らしいチュートリアルを書きました。その中でシグナルの競合状態
をいかに排除するかについて、アドバイスをしています。さらに情報を得たい
なら要約を読むようにおすすめします。ここに書くものは、私が推奨すること
ですが、Michal 氏のものと同様です。

 ・ 可能な限りどんな場合でも、シグナルハンドラは特定のフラグを設定する
    だけにして、他に何もさせないようにしてください。
   
 ・ より複雑なシグナルハンドラを実装せざるを得ないなら、シグナルハンド
    ラで使用しても安全である、特に指定があるものだけを利用するようにし
    てください。特に、C の malloc() や free()(シグナルから保護されてい
    ないシステムが大半) だけでなく、malloc() と free()に依存しているた
    くさんの関数(printf() ファミリーや syslog()等)を使用しないでくださ
    い。「ラッパー」を作って、安全でないライブラリを呼び出すことも可能
    です。ラッパーで再入を防ぐためにグローバルなフラグをチェックします
    。しかしお勧めはしません。
   
 ・ プログラム中でアトミックでない操作を行っている間は、シグナル送出を
    ブロックし、シグナルハンドラ内部でもシグナル送出をブロックしてくだ
    さい。
   
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

3.6. Quota とリソースの制限

Unix ライクなシステムの多くは、ファイルシステムの割り当て制限(quota)と
プロセスのリソース制限を行なう機能を持っています。もちろん Linux も持っ
ています。この仕組みはサービス拒否攻撃を防ぐのに特に役立ちます。各ユー
ザが利用できるリソースを制限することで、単独ユーザがシステム全体のリソ
ースを食い尽くしにくくできます。この機能には、「ハードな制限」(hard
limit)と「ソフトな制限」(soft limit)両方の意味があり、多少意味が異なる
ので、注意が必要です。

記憶装置(ファイルシステム)の割り当て制限は、マウントポイント毎に設定が
可能で、特定のユーザやグループがそこで使用できるブロック数やファイル数
(inode数)に制限をかけられます。「ハードな」ものが制限を越えることができ
ないのに対して、「ソフトな」ものは一時的に制限を越えることが許されてい
ます。 quota(1)、quotactl(2)、quotaon(8)を参照してください。

rlimit は、プロセスに対する数々の割り当て制限を実現する仕組みで、ファイ
ルサイズや子プロセス数、オープンできるファイル数等を扱えます。「ソフト
な」制限(現状の制限(current limit)とも言う)と「ハードな制限」 (上限
(upper limit)とも言う)があります。ソフトな制限を超えることは決してでき
ませんが、システムコールによってハードの上限までもっていくことができま
す。 getrlimit(2)や setrlimit(2)、getrusage(2)、sysconf(3)、ulimit(1)を
参照してください。制限をかける方法がいくつかあることに注意してください
。PAM モジュールである pam_limits もその 1 つです。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

3.7. ダイナミックリンク・ライブラリ

プログラムを実行するには、実際ライブラリが必要となります。 Linux を含む
最近の Unix ライクなシステムの大半は、プログラムはデフォルトでダイナミ
ックリンク・ライブラリ(DLL)を使ってコンパイルしてあります。つまりあるラ
イブラリを更新すれば、そのライブラリを使っているプログラムすべてが新し
い(うまくいけばより良い)バージョンになります。

普通ダイナミックリンク・ライブラリは、特別なディレクトリ数ヶ所に存在し
ます。通常は、/lib や /usr/lib、 PAM モジュールの /lib/security、 X
Window System の /usr/X11R6/lib、 /usr/local/lib がそれに当たります。プ
ログラムは、この標準的な慣例を使うようにしてください。デバッグ時を除い
ては、カレントディレクトリからダイナミックリンク・ライブラリが存在する
所をたどっていけるような値を使わないでください(攻撃者が好みの「ライブラ
リ」を追加できてしまうかもしれません)。

ライブラリに名前を付けたり、シンボリックリンクを張る場合に特別な約束事
が存在します。その結果として、ライブラリを新しくしても、古くて、バック
ワード・コンパチビリティがないバージョンのライブラリをサポートできます
。また、特定のライブラリや特別なプログラムを実行する時に、あるライブラ
リの特定の関数だけを変更する方法も複数あります。 Unix ライクなシステム
が Windows ライクなシステムと比べて、極めて優れている点がこれです。Unix
ライクなシステムはライブラリの更新を行う点では、より優れたシステムだと
思います。この優れた点が一因となり、Windows ベースのシステムより Unix
や Linux システムの方が安定していると考えています。

Linux システムすべてを含む GNU glibc ベースのシステムでは、ディレクトリ
の一覧は /etc/ld.so.conf に保存してあり、プログラムは起動する間に自動的
に検索しています。 Red Hat がベースとなっているディストリビューションで
は、普通は /usr/local/lib は /etc/ld.so.conf に記述してありません。私は
これをバグの 1 つだと見なしています。/usr/local/lib を /etc/ld.so.conf
に追加するのは、プログラムの多くを動かすのに必要な作業です。この作業は
、Red Hat がベースとなっているシステムで共通の「フィックス」作業になっ
ています。あるライブラリの関数をいくつかだけ変更したいが、その他はその
まま使いたい場合は、優先して使いたいライブラリ(.o ファイル)の名前を /
etc/ld.so.preload に記入してください。この「先読み(preloading)」ライブ
ラリは、標準で用意してあるものに先がけてロードされます。この先読みファ
イルは、緊急パッチ用によく使います。ディストリビューションでは、配布時
にはそのようなファイルは使用しません。起動時にディレクトリをすべて検索
するのはあまりに時間の無駄なので、実際にはキャッシュを使って処理してい
ます。 ldconfig(8)はデフォルトで /etc/ld.so.conf を読んで、ダイナミック
リンク・ライブラリのあるディレクトリにシンボリック・リンクを適切に張っ
て設定し (したがって、標準的な慣例にしたがった方が良い)、キャッシュ情報
を /etc/ld.so.cache に書きます。他のプログラムはそのキャッシュを利用し
ます。つまり、ldconfig は DLL が追加されたり、DLL が削除されたり、DLL
のディレクトリごと変更されたりした場合には必ず動かさなければいけません
。ライブラリをインストールした時にパッケージ・マネージャが作業の 1 つと
して ldconfig を動かす場合がよくあります。プログラムを起動すると、ダイ
ナミック・ローダーを使って /etc/ld.so.cache を読み、必要となるライブラ
リをロードします。

さまざまな環境変数がこの過程をコントロールできます。実際、この過程を変
更してしまう環境変数も存在します(たとえば、一時的に別のライブラリに置き
換えて、実行できます)。 Linux では、環境変数 LD_LIBRARY_PATH はコロン
(:)で区切って記述してあるディレクトリの集まりで、ライブラリをまずここか
ら検索し、その後に標準的なディレクトリを検索します。新しいライブラリを
デバッグしたり、特定用途のために非標準のライブラリを使用する時に役に立
ちます。ただ、そのディレクトリを管理できる人間を信頼することになります
。注意してください。環境変数 LD_PRELOAD はオブジェクトファイルの一覧で
、標準的なライブラリから変更する関数を含んでいます。/etc/ld.so.preload
がまさにそれです。環境変数 LD_DEBUG はデバッグ情報を表示します。「all」
と指定すると、ダイナミックリンクしているプロセスについて、実行中に膨大
な情報を表示します。

ユーザがダイナミックリンク・ライブラリをコントロールできるようになると
、何らかの手当てをしない限り、setuid や setgid したプログラムが面倒なこ
とになります。そのため、GNU glibc の実装では、プログラムに setuid や
setgid してあるとこれらの環境変数(加えて同じような変数も)を無視するか、
動作に大幅な制限をかけます。 GNU glib ライブラリは、プログラムの権限を
チェックして setuid もしくは setgid を判断しています。 uid と euid が違
っているか、gid と egid が違っていれば、ライブラリはそのプログラムが
setuid もしくは setgid(もしくはそれを継承)していると仮定し、その結果、
機能を大幅に制限し、リンクを管理します。 GNU glib ライブラリをロードし
てみればわかります。特に elf/rtld.c と sysdeps/generic/dl-sysdep.c を見
てください。 uid と gid を euid と egid に等しくしてプログラムを呼び出
せば、環境変数は機能をすべて働かせます。他の Unix ライクなシステムでは
、理由は同様である点は別として、状況が変わります。setuid もしくは
setgid したプログラムは環境変数にむやみに影響を受けるべきではありません
。

Linux システムについては、私の著作である Program Library HOWTO <http://
www.dwheeler.com/program-library> から情報をさらに得られます。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

3.8. Audit(監査)

Unix ライクなシステムは、それぞれ異なる方法で監査しています。 Linux で
最も一般的な「監査」の仕組みは syslogd(8)で、klogd(8)とともに動いていま
す。 wtmp(5)や utmp(5)、lastlog(8)、acct(2)も参照することをお勧めします
。サーバプログラム(Apache Web サーバのようなもの)は、独自に痕跡を監査す
る仕組みを持っているものもあります。 FHS によれば、監査ログは /var/log
もしくは、そのサブディレクトリに保存した方がよい、としています。 

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

3.9. PAM

Sun Solaris やほとんどすべての Linux システムでは認証が必要な時に、
Pluggable Authentication Modules(PAM: 差し替え可能な認証モジュール)を使
用します。 PAM を使えば、実行時に認証方法の設定を変更できるようになりま
す(たとえばパスワードやスマートカード等の使用)。 PAM の利用方法について
詳細な情報は、Section 10.6 を見てください。【訳註：スマートカード(smart
card)とは、プラスティックのカード上に IC やメモリ等のチップを載せたカー
ドを指します。日本では IC カードと呼ぶケースが多いようです。従来の磁気
カードと比べると、より多くの情報を格納できるだけではなく、プログラムを
インストールして実行することが可能である点が大きく異なります】

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

3.10. Unix ライクなシステムに固有なセキュリティ拡張機能

Unix ライクなシステムを拡張すべく、さまざまなコミュニティがいろいろな調
査や開発に力を注いでいます。たとえば、Unix ライクなシステムのいくつかで
は機能を拡張して、米軍が求める階層構造を持ったセキュリティをサポートし
ています。ソフトウェアを開発するなら、設計する時にこの拡張機能を実現で
きるように頑張ってみてください。

FreeBSD は新しいシステムコールである jail(2) <http://docs.freebsd.org/
44doc/papers/jail/jail.html> を持っています。 jail というシステムコール
は環境を複数に分割し、仮想マシンをたくさんサポートします(ある意味、「ス
ーパー chroot」と言えます)。利用方法としては、インターネット・サービス
・プロバイダの環境で、仮想マシンのサービスとして利用するのが大半です。
1 つの jail の内部では、すべてのプロセス(root が所有者であっても)はその
jail の範囲に命令が限定されます。 FreeBSD システムを新規インストールし
た後にブートすると、 jail に入るプロセスは 1 つもありません。プロセスが
jail に入ると、そのプロセスとそこから派生するプロセスはすべて jail に入
ります。 jail に入ってしまえば、ファイル名空間へのアクセスは chroot(2)
スタイルで制限を受けます(chroot を避けようとしてもブロックされます)。ネ
ットワークリソースを利用する機能は、特定の IP アドレスに制限され、シス
テムリソースの操作や権限をいじる行為は、大幅に切り詰められ、他のプロセ
スとのやりとりは、同じ jail の中のプロセスにだけ制限されます。 jail そ
れぞれは、1 つの IP アドレスを使っています。jail の中のプロセスは、他の
IP アドレスを使って外部とやりとりはできない点に注意してください。【訳註
：jail(2)の日本語マニュアルはhttp://www.jp.freebsd.org/cgi/mroff.cgi?
subdir=man&lc=1&cmd=&man=jail&dir=jpman-5.0.0%2Fman&sect=0 にあります】

Linux では拡張機能が利用可能です。たとえば先に論じた POSIX ケイパビリテ
ィやマウント時の特殊なオプションがそれに当たります。 Linux システムで実
行環境を制限する試みをいくつか挙げておきます。アプローチの仕方はさまざ
まです。 U.S. National Security Agency(NSA)では Security-Enhanced Linux
(Flask) <http://www.nsa.gov/selinux> を開発し、特殊な言語でセキュリティ
・ポリシを定義し、それに基づきポリシを実施します。 Medusa DS9 <http://
medusa.fornax.sk> は Linux を拡張し、カーネルレベルでユーザ空間で動く認
証サーバをサポートしています。 LIDS <http://www.lids.org> は、ファイル
やプロセスを保護し、管理者にシステムを「封鎖(lock down)」する権限を与え
ています。「ルールベースのアクセス制御」システム RSBAC <http://
www.rsbac.de> は、アクセス制御に汎用的なフレームワーク(Generalized
Framework for Access Control (GFAC))を用いています。これは Abrams 氏と
LaPadula 氏によって作られ、複数のカーネルモジュールによって、柔軟なアク
セス制御を実現しています。 Subterfugue <http://subterfugue.org>は、「ソ
フトウェアの実態をもって監視、実行する」というフレームワークです。サン
ドボックスやトレーサ等を実行することで、システムコールを横取りし、その
パラメタや返り値を変更します。 Linux 2.4 で動作し、何も変更はいりません
(カーネルモジュールの追加は何も必要ありません)。 Janus <http://
www.cs.berkeley.edu/~daw/janus> はセキュリティツールで、制限された実行
環境下で信頼できないアプリケーションをサンドボックスに閉じ込めます。 
User-mode Linux <http://user-mode-linux.sourceforge.net> は、サンドボッ
クスの実装の 1 つで、「Linux 上で Linux を動かす」ことを実現しています
。このようにさまざまなアプローチによって、より洗練したセキュリティモデ
ルを実装していますので、Linus Torvalds 氏は、異なるセキュリティ・ポリシ
でも採用できるような汎用的アプローチを開発して欲しい、と要望しています
。詳しくは、 http://mail.wirex.com/mailman/listinfo/
linux-security-module を見てください。

さまざまな Unix ライクなシステム上で、他にもいろいろなセキュリティ上の
拡張が存在しています。しかし、このドキュメントでは範囲外なので扱いませ
ん。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

Chapter 4. 入力されるものすべてを検証すること

                                    あなたは悪い道から救い出され、暴言 
                                    をはく者を免れることができる。     
                                                                       
                                                旧約聖書箴言 2 章 12 節

入力には、信頼できないユーザからのものもあります。そこで、使用する前に
それらを検証(選別)する必要があります。まず何が正しいかを定義して、その
定義にマッチしないものすべてを拒否するようにしなければいけません。その
逆の定義の仕方をしてはいけません(何が不正かを定義し、それらを拒否する)
。なぜなら、重大なケースをうっかり定義し忘れてしまうかもしれないからで
す。

ですが、検証コードが完全なのかを確認するために、テスト用(たいていは頭の
中で実行)で「不正な」値を定義するのは良いことです。私は入力フィルタを設
定した時には、頭の中でフィルタを攻撃してみて、不正な値がフィルタを通り
抜けないかを見てみます。入力内容にもよりますが、ここでは代表的ないくつ
かの「不正な値」の例をあげてみます。これらは入力時にフィルタで防御する
必要がある値です。空文字や「.」、「..」、「../」、「/」や「.」ではじま
る文字列や「/」もしくは「&」を含む文字列、すべての制御文字(特に NIL や
改行)もしくは「ハイビット」の文字(特に十進数で 254 と 255)がそれです。
繰り返しますが、コードは「悪い」値でチェックすべきではありません。頭の
中であなたが書いたパタンが容赦なく入力を制限して、正しい値だけを通すの
かどうかを確かめるためです。もしそのパタンで十分に制限していなければ、
注意深くパタンを再調査して、他の問題がないか確認する必要があります。

最大文字数(適切なら最小文字数も)を制限して、文字数を超えても制御不能に
ならないようにしてください (バッファオーバーフローについての詳細は 
Chapter 5 を見てください)。

ここではデータタイプとしてよく使われるものをいくつか挙げます。信頼でき
ないユーザからのデータを利用する前に、必ず検証するようにしてください。

 ・ 文字列に対しては、正しい文字やパタン(たとえば、正規表現として)を識
    別し、それに沿わないものすべてを拒否してください。文字列に制御文字
    (特に改行や NIL)やメタキャラクタ(特にシェルのメタキャラクタ) がある
    と特殊な問題が発生します。入力があったら、速やかにメタキャラクタを
    「エスケープ」するのが最善です。入力が間違って渡らないようにするた
    めです。 CERT はそれ以上に、[CERT 1998、CMU 1998] にあるエスケープ
    する必要のない文字のリストに載っていない文字すべてをエスケープする
    ように推奨しています。メタキャラクタについての詳しい情報は、Section
    7.3 を見てください。
   
 ・ 数字すべてに対して、許容できる最小値(たいていはゼロ)と最大値を設け
    てください。
   
 ・ 電子メールのアドレスを完全にチェックするのは、現実的にとても困難で
    す。というのも、すべてのケースを真面目にサポートしようとすると、ア
    ドレスの中には正しい形式ではあるものの、非常に複雑な検証を必要とす
    るアドレスが存在するからです。もしそのようなチェックが必要なら、詳
    細は mailaddr(7)と IETF RFC 822 [RFC 822]を見てください。たいていは
    、「一般的な」インターネット・アドレス形式だけを単純に許可すればよ
    いでしょう。【訳注：IETFは、Internet Engineering Task Force の略称
    で、インターネットに関連する技術の標準化を進めるために設立された団
    体です。ここが発行する文書が RFC(Requests For Comment)です】
   
 ・ ファイル名をチェックしてください。普通、信頼できないユーザからは、
    「..」 (上位ディレクトリ)という値を正しいものとして受け取りたくない
    でしょう。しかし、それは環境に依存しています。また、許可した文字だ
    けを載せてもよいかもしれません。特に改行(問題を起こす可能性がありま
    す)は、問題なければ削除してください。ファイル名においては、ディレク
    トリにおけるどんな変更も禁止するのが最善の策です。たとえば、「/」を
    正しい文字として扱わない等。「glob」をサポートしてはいけません。つ
    まりファイル名を拡張するような「*」や「?」、「[」(「]」に対応)」さ
    らに「{」(}に対応)」等です。たとえば、「ls *.png」というコマンドは
    「*.png」を全 PNG ファイルのリストに glob します。 C の fopen(3) コ
    マンド(たとえば)は、glob しませんが、コマンドシェルは、デフォルトで
    glob します。また C では(たとえば)glob(3)を使って glob 機能を利用で
    きます。 glob が必要なければ、 glob しないシステムコール(たとえば
    fopen(3)だけをできるだけ使用するか、無効にしてください(たとえばシェ
    ルで glob する文字をエスケープする)。 glob を許可するなら、細心の注
    意を払ってください。 glob は便利に使えますが、glob を複雑にするとコ
    ンピュータにかなりの負荷をかけることになります。たとえば、ftp サー
    バには glob 命令をいくつか要求すると、いとも簡単にマシン全体でサー
    ビス拒否攻撃状態になるものもあります。
   
    ftp> ls */../*/../*/../*/../*/../*/../*/../*/../*/../*/../*/../*/../*
   
    glob を許可しているにもかかわらず、glob するパタンに制限をかけない
    と、困ったことになるでしょう。そのようなプログラムは、独立したプロ
    セスとして走らせ、プロセスが消費する CPU 利用量やその他リソースに必
    ず制限をかけてください。 Section 6.4.8 にこの方法についてのさらに詳
    しい情報があります。また、Section 3.6 にこれらの制限のかけ方につい
    て詳しい情報がありますので、見てください。
   
 ・ URI(URL を含む)が妥当なのか、チェックしなければいけません。ある URI
    を直接操作するなら(つまり、Web サーバや Web サーバもどきのプログラ
    ムを実装していて、要求されるデータが URL の場合)、URI が正しいかど
    うかを確認しなければなりません。また URI で特に注意を払うケースは、
    ドキュメントルート(サーバが返すファイルシステム領域)を「回避」しよ
    うとするものです。ドキュメントルートを回避する最も一般的な方法は、
    「..」やシンボリックリンクを経由する方法です。したがって大半のサー
    バは、どんな「..」ディレクトリもチェックしており、シンボリックリン
    クは特に指示がない限りは無視します。また、エンコード(URL エンコード
    や UTF-8 エンコード)してあるものは、まずデコードすることを忘れない
    でください。でないとエンコードされた「..」がすり抜けてしまいます。
    URI は UTF-8 エンコードが入ることを前提としていませんので、ハイビッ
    ト文字が入った URI すべてを拒否するのが最も安全です。
   
    データとして URI(URL)を扱うシステムの実装をしているなら、簡単にでき
    るとは夢々思わないでください。悪意あるユーザが他のユーザに迷惑をか
    けるような URI を入れ込むことが絶対ないようにしなければいけません。
    さらに詳しい情報は Section 4.10.4 を見てください。
   
 ・ クッキーで値を受けとった時には、利用しているクッキーがどんなもので
    あっても、ドメイン値が予期した値であることを必ずチェックしてくださ
    い。さもないと、 (おそらくクラックされた)関連サイトが偽のクッキーを
    入れ込んでしまう可能性があります。ここでは、このIETF RFC 2965 で書
    いてある例をあげます。このチェックをしくじるとどのような問題が生じ
    るかについて記述してあります。
   
     □ ユーザ側が victim.cracker.edu にリクエストを出し、クッキーが
        session_id="1234" と返ってきて、デフォルトのドメインを
        victim.cracker.edu に設定します。
       
     □ ユーザ側は spoof.cracker.edu にリクエストを出し、クッキーが
        Domain=".cracker.edu" で session-id="1111" と返ってきます。
       
     □ 再度ユーザ側は victim.cracker.edu にリクエストを出し、下記を渡
        します。
       
                 Cookie: $Version="1"; session_id="1234",                       
                         $Version="1"; session_id="1111"; $Domain=".cracker.edu"
       
        victim.cracker.edu のサーバは、2 番目のクッキーがドメイン属性が
        自分のそれと違っていることから、自分のものではないことを検知し
        、無視しなければいけません。
       
問題を解決できないなら、正しい文字パタンには、プログラム内部や最終的な
出力に対して特別な意味を持つ文字もしくは文字列を含めてはいけません。

 ・ ある文字の連続が、プログラムの内部に持っている書式に対して、特別な
    意味を持つ場合があるかもしれません。たとえば、保存するデータに区切
    りのある文字列を使うなら(内部でも外部でも)、区切り文字をデータ値と
    することを必ず禁じてください。テキストファイルに保存してあるデータ
    に、カンマ(,)やコロン(:)を区切りとして使っているプログラムはたくさ
    んあります。入力に区切り文字が入っていて、プログラムがそれに対処(す
    なわちそれを阻むか、何らかの方法でエンコードする)していなければ、問
    題が発生するかもしれません。他の文字でも、これらの問題が発生する場
    合がよくあります。それは、他の文字の中にシングルもしくはダブル・ク
    ォーテーション(文字列を囲むのに使用)や小なり記号「<」(SGML や XML、
    HTML ではタグの開始を示す識別に使われています。これらのフォーマット
    でデータを保存する場合、この記号は重要です)が入っているケースです。
    大半のデータフォーマットは、エスケープシーケンスを用意して、このよ
    うなケースに対処しています。そのエスケープシーケンスを使うか、入力
    データをフィルタしてください。
   
 ・ ユーザに対してある文字の連続が戻される場合に、特別な意味を持つケー
    スがあります。一般的な例として、HTML のタグを入力として認める場合、
    後になってそれを他のユーザにポストすることがあります(たとえば、ゲス
    トブックや「読者のコメント」コーナー)。しかし、この問題は広く影響を
    及ぼしています。この話題についてさらに全体的な議論は、 Section 6.15
    を、HTML のフィルタリングについて特化した議論は Section 4.10 を見て
    ください。
   
これらのテストは 1 ヶ所で集中して行ってください。そうすれば、そのテスト
が正しいかどうか、後になって簡単に調査できます。

正しい入力をチェックするテストが、予定した通り確実に動作するようにして
ください。別のプログラムが使う入力(ファイル名や電子メールアドレス、URL
等)をチェックする場合には特に重要です。これらのプログラムは、見落としが
ちな間違いを抱えていることが多く、いわゆる「代理人問題」(データを実際に
使用するプログラムとチェックするプログラム間で前提条件が異なっているケ
ース)が発生します。適切な規準があるなら、それを見てください。あわせて、
そのプログラムが、拡張機能を持っていないかどうかの調査もしてください。
拡張機能は知っておく必要があります。

ユーザの入力を解析している間は、一時的に特権すべてを落とすというのは良
い考えです。また独立したプロセスを作成するのも、同じく良い考えです (解
析を行う場合は常に特権を落とし、他のプロセスが解析の要求に対してセキュ
リティ上のチェックを行う)。このケースがとりわけ当てはまるのは、解析作業
が複雑である場合(たとえば、lex や yacc といったツールを使う)や、プログ
ラミング言語がバッファオーバーフローを防げない場合です(たとえば、C や
C++)。特権を最小限にする方法については Section 6.4 を見てください。

セキュリティ上の判断を行う際にデータを使用する時には(たとえば「このユー
ザを通過させなさい」)、必ず信頼できる経路を使ってください。たとえば、公
開されたインターネット上では、マシンの IP アドレスやポート番号だけにユ
ーザの認証を任せてはいけません。というのは、この情報を(もしかすると悪意
を持った)ユーザが設定できてしまう環境が大多数だからです。詳しい情報は 
Section 6.11 を見てください。

下記のサブセクションでは、プログラムに対するさまざまな入力について論じ
ます。環境変数や umask 値等、プロセスの状態を含む入力には注意が必要です
。入力すべてが信頼できないユーザによってコントロールされているわけでは
ないので、これから論じる入力だけを気にかければ OK です。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.1. コマンドライン

プログラムは、コマンドラインから入力を取ってくる場合がよくあります。
setuid や setgid したプログラムに対するコマンドライン上のデータは、信頼
できないユーザが入力しています。したがって、コマンドラインの値が敵意あ
るものである場合に備えて、setuid や setgid したプログラムはプログラム自
身でそれに対処しなければいけません。攻撃者は、ほとんどあらゆる種類のデ
ータをコマンドラインから入力できます (execve(3)のようなシステムコールを
呼び出すことで)。したがって、setuid や setgid したプログラムは、コマン
ドライン上の入力を完璧に検証し、コマンドラインの引数が 0 番目に当たるプ
ログラム名を信頼してはいけません(攻撃者は NULL を含むどんな値も設定でき
るため)。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.2. 環境変数

環境変数は、デフォルトでは親プロセスから継承されます。しかしあるプログ
ラムから別のプログラムを実行(exec)した場合、環境変数に任意の値を設定で
きます。 setuid や setgid されたプログラムでは、これは危険です。という
のも、プログラムを呼び出すことで環境変数のコントロールが可能になり、環
境変数を別のプログラムに渡せてしまうからです。通常、環境変数は継承され
てしまうため、この危険性も同時に引き継がれてしまいます。安全性が必要な
プログラムが他のプログラムを何も考えずに呼び出すと、もしかすると危険で
ある環境変数の値がそのプログラムが呼び出すプログラムに渡されてしまうか
もしれません。下記のサブセクションでは、環境変数とその取り扱いについて
論じます。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.2.1. 環境変数の中には危ないものもある

環境変数の中には危険なものがあります。理由は、たいていの場合ライブラリ
やプログラムは環境変数によってコントロールされているものの、その方法が
あいまいだったり、わかりにくかったり、ドキュメント化されていないものが
あったりするからです。たとえば IFS 変数は、sh や bash でコマンドライン
の引数を分割するために使用するキャラクタの指定で利用されています。シェ
ルは低レベルのシステムコール(C の system(3) や popen(3)や Perl の
backtick 演算子)を利用して呼び出されるため、IFS 変数に異常な値を設定す
ると、一見安全と思われるシステムコールを危険なものに変えてしまう恐れが
あります。この動作は bash や sh のドキュメントに載っていますが、はっき
りとは書いてありません。長年愛用している人だけが、IFS を知っています。
それは IFS を使うとセキュリティが脅かされるという理由であって、本来の目
的で実際によく使われるからではありません。さらに困ったことに、すべての
環境変数がドキュメント化してあるわけではなく、ドキュメント化してあった
としても、その他のプログラムが値を変更したり、危険な環境変数を追加して
しまう可能性もあります。つまり、唯一の解決方法(下記にあげますが)は、必
要な環境変数を選び出し、残りを捨てることです。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.2.2. 環境変数の保存方法にまつわる危険性

本来プログラムは、標準的なアクセス手段で環境変数を利用した方がベターで
す。たとえば、C では値を取得するのに getenv(3)を使い、値を設定するのに
POSIX 規格である putenv(3)を使うか、BSD の拡張である setenv(3)を使いま
す。また環境変数を削除するのには、unsetenv(3)を使います。ここで強調して
おきたいのは、setenv(3)が Linux でも実装されていることです。

しかし、攻撃者はそのように行儀よくする必要はありません。攻撃者は環境変
数のデータ領域を直接コントロールし、そのデータ領域を execve(2)を使った
プログラムに渡せます。これが悪意ある攻撃を可能にしています。この攻撃は
環境変数が実際にどのように動作するかを理解してはじめて理解できる攻撃で
す。 Linux では environ(5)を見れば、要約したかたちで環境変数がどのよう
に機能するかがわかります。簡単に言えば、環境変数は文字に対するポインタ
の配列へのポインタとして記憶しています。この配列は規則正しく並んでいて
、NULL ポインタで終端してあります (したがって、配列の最後がわかります)
。同様に文字へのポインタは、それぞれが NIL で終端してある「名前=値」と
いうフォーマットの文字列の値をそれぞれ指しています。これが言わんとする
ことは、いくつかあります。たとえば環境変数名には、イコール記号(=)を入れ
ることができません。名前だけでなく値にも NIL 文字を埋めこめません。しか
し危ないと言う意味では、同じ名前でありながら値が異なる複数のエントリ
(たとえば、複数の SHELL 変数値)を認めるというものもあります。代表的なコ
マンドシェルは、これを禁止していますが、攻撃者がローカルで作業していれ
ば、execve(2)を使ってそのような状況を作れます。

この書式を記録(設定する方法も)する上での問題は、プログラムが (正しい値
であるかを見るために)これらの値の 1 つをチェックすればよいのに、実際は
違うものを使ってしまう点にあります。 Linux では GNU glibc ライブラリが
この問題からプログラムを保護することに取り組んでいます。 glibc 2.1 にお
ける getenv の実装は、常に最初にマッチした項目を取得し、 setenv と
putenv は常に最初にマッチした項目に設定します。unsetenv は、マッチした
項目すべてを解除します(GNU glibc の実装は何と素晴らしいことか！)。しか
し、プログラムには環境変数に直接アクセスし、環境変数すべてをなめるもの
もあります。この場合は、プログラムが最初ではなく、最後にマッチした項目
を使う可能性があります。となると、最初の項目をチェックしているにもかか
わらず、実際は最後の項目を使ってしまうことになります。攻撃者はこの事実
を利用して、保護ルーチンを回避してしまいます。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.2.3. 解決方法――選別して、消し去る

setuid や setgid してあるプログラムを安全にするには、入力として必要な環
境変数(があれば)を減らして、周到に選別しなければいけません。そして環境
変数全体を消し、その後必要となるわずかな数の環境変数に、安全な値を再設
定します。何らかの下位プログラムを呼び出すなら、これが一番優れた方法で
す。「危険な値をすべて」をリストアップする手法は、実質的ではありません
。直接間接に呼び出すプログラムごとにソースコードをレビューしたとしても
、あなたがコードを書いた後に、ドキュメント化していない新たな環境変数を
誰かが追加してしまうかもしれません。そういうものの 1 つが危険であるかも
しれません。

C や C++ で簡単に環境を消去する方法は、グローバル変数の environ に NULL
を設定してしまう方法です。グローバル変数である environ は <unistd.h>;
で定義してあり、C や C++ ユーザはこのヘッダーファイルを #include する必
要があります。まずこの値を処理してから、スレッドを立ち上げなければいけ
ませんが、それが問題となることはめったにありません。というのは、プログ
ラムを実行する際、できるだけ早い段階(通常はスレッドを起こす前)でこれら
の処理を行う必要があるからです。

グローバル変数 environ はさまざまな規格で定義してあります。公式な規格で
直接値を変更することを認めているかどうかははっきりしません。しかし直接
値を変更することで問題が発生してしまうような Unix ライクなシステムを私
は知りません。私は通常「environ」だけを直接修正しています。そのような低
レベルの構成要素で処理すると、おそらく互換性はなくなります。しかし確実
にクリーン(で安全)な環境を得ることが保証されます。環境変数全体に対して
、後になってアクセスが必要なケースが時として生じるので、「environ」変数
の値をどこか別のところに保存しておくのもよいでしょう。しかし、プログラ
ムにはほんのいくつかの値が必要な場合がほとんどなので、残りは落とすほう
がよいでしょう。

もう 1 つ環境をクリアにする方法があります。それは clearenv()というドキ
ュメントにのっていない関数を使う方法です。この clearenv()関数は生い立ち
が変わっています。POSIX.1 では定義されることになっていましたが、どうい
うわけか規格には入りませんでした。しかし、clearenv()は POSIX.9(Fortran
77 の POSIX 規約)で定義しているので、準公式扱いになっています。 Linux
で clearenv()は、<stdlib.h> で定義してありますが、#include を使って取り
込む前に、必ず __USE_MISC が #defined していなければいけません。もう少
し「公式」なアプローチとして __USE_MISC を定義するのに、まず
_SVID_SOURCE もしくは _BSD_SOURCE をまず宣言してから、 #include
<features.h> してください。これらはテスト用マクロとして公式の機能です。
__

PATH は、追記されるタイプの環境変数の 1 つです。ディレクトリのリストに
なっていて、プログラムを検索するのに使用します。PATH には、カレントディ
レクトリを含めてはいけません。普通は単純に「/bin:/usr/bin」という感じに
します。 IFS(デフォルトは「 \t\n」で、最初の文字はスペースです) や TZ
(タイムゾーン)も設定しているかもしれません。 Linux は IFS や TZ を設定
していなくても、止まることはありません。しかし、 System V ベースのシス
テムの中には、TZ に値を設定しないと問題が起こるものもあります。また、
IFS に値を設定していないとまずいシェルがあるようです。 Linux では
environ(5)を見て、一般的な環境変数の一覧を確認し、設定したい変数を見つ
けた方がよいでしょう。

ユーザが提供する値を本当に必要とするなら、まず値をチェックしてください
(値が正式な値のパタンにマッチしているか、許容している最大文字列長を超え
ていないかを確認してください)。 /etc に、「安全な環境変数の基準」を示し
た、信頼できる基準となるファイルが存在するのが理想です。しかし現状は、
この目的に合致した基準となるファイルは存在しません。似たようなものとし
て、もしシステム上に PAM モジュールがあるなら、pam_env を調べた方がよい
でしょう。 

シェルをプログラミング言語として使っているなら、「/usr/bin/env」に「-」
オプションを利用します(これで動作するプログラムの環境変数すべてが削除さ
れます)。つまり、/usr/bin/env を「-」オプション付きで呼び出して、その後
に変数を準備し、それに値を設定します(名前=値の形で)。次に、プログラムに
引数を与えて起動します。通常はプログラムをフルパス(/usr/bin/env)で指定
してください。ただ「env」としないでください。そうするとユーザが危険な
PATH の値を作成してしまいます。 GNU の env には「-i」とその同義である「
--ignore-environment」(これもプログラムが起動すると環境変数を削除する)
がありますが、他のバージョンとは互換性がありません。

setuid や setgid するプログラムを作成していて、その開発言語が環境を直接
再設定できないなら、「ラッパー」プログラムを作成するのも手の 1 つです。
ラッパーは、プログラムの環境を安全な値に設定し、他のプログラムを呼び出
します。注意しなければいけないのは、ラッパーが対象となるプログラムを実
際に呼び出さなければいけない点です。そのプログラムがインタプリターなも
のなら、競合状態に絶対に陥らないようにしてください。競合状態が起こると
、特別に権限を許可して setuid や setgid してあるプログラムではなく、別
のプログラムをインタプリターがロードしてしまうかもしれないからです。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.3. ファイル・ディスクリプタ

プログラムには「オープンしたファイル・ディスクリプタ」、つまりあらかじ
めオープンされているファイルが渡ります。 setuid や setgid されたプログ
ラムでは、オープンしているファイルとその内容をユーザが(パーミッションの
範囲内で)切り替えられる、ということに配慮する必要があります。 setuid や
setgid されたプログラムでは、新しくオープンしたファイルが常に固定したフ
ァイル・ディスクリプタ ID に割り当てられていると想定してはいけません。
また端末が標準入力や標準出力、標準エラーの出力先になっていること、また
端末が既にオープンされていることも前提にしてはいけません。

この理論的根拠は難しくありません。攻撃者がプログラムを起動する前にファ
イル・ディスクリプタをオープンしたりクローズしたりできますので、攻撃者
は予想外の状況にしようと思えばできてしまいます。攻撃者が標準出力を閉じ
、その時にプログラムが次のファイルをオープンした時に、あたかも標準出力
がオープンしているかのようになります。そしてプログラムは、すべて標準出
力に書くがごとく、そのファイルに書き込んでしまいます。 C ライブラリの中
には、stdin や stdout、stderr が開いていなければ(/dev/null に対して)、
自動的にオープンするものがあります。しかしこれは Unix ライクなシステム
すべてに当てはまるわけではありません。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.4. ファイルの内容

ファイルの内容によって、プログラムの動作が左右される場合、信頼できるユ
ーザだけがその内容を変更できるのでなければ、そのファイルを信用してはい
けません。つまり信頼できないユーザが、ファイルやそのファイルがあるディ
レクトリ、その親ディレクトリを修正できてはいけません。そうでないなら、
そのファイルを信頼するに値しないものとして扱わなければいけません。

ファイルに記述してあるやり方が、信頼できないユーザからのものだとするな
ら、このドキュメントに書かれている内容にしたがって、そのファイルからの
入力を防いでください。特に正しい値とマッチしているか、バッファがオーバ
ーフローしないかを必ずチェックしてください。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.5. Web ベースのアプリケーションの入力(特に CGI スクリプト)

Web ベースのアプリケーション(CGI スクリプトのような)は、信頼できるサー
バ上で稼働し、何らかの方法で Web 経由で入力データを受け取る必要がありま
す。入力は概して信頼できないユーザから来ますので、この入力データを検証
する必要があります。実際、情報は信頼できない第三者からやってきます。
Section 6.15 にさらに詳しい情報があります。たとえば、CGI スクリプトは、
情報を標準的な環境変数や標準入力を通じて取得します。このドキュメントの
残りの部分では、CGI にターゲットを当てて論じるつもりです。理由は、CGI
が動的に Web コンテンツを実行する最も普及している技術であり、他の動的に
Web コンテンツを実行する技術も一般的な問題点は同じだからです。

CGI からの入力の多くが、いわゆる「URL エンコードされた」形式になってい
る点が、検証をより厄介にしています。つまり 16 進数の HH というバイト値
を表すには %HH という形式をとります。 CGI や CGI ライブラリは、これらの
入力を適切にデコードして、バイト値が正しいかどうかをチェックする必要が
あります。 %00(NIL)や %0A(改行)のような疑わしい値を含むすべての入力を間
違いなく処理しなければいけません。入力のデコードは繰り返し行わないでく
ださい。そうしないと、「%2500」のような入力が、誤って処理されてしまいま
す(まず %25 が「%」に変換され、その結果「%00」が間違って NIL キャラクタ
に変換されてしまいます)。

入力に特殊なキャラクタを混ぜることで、CGI スクリプトを攻撃するケースが
まま見られます。上記の解説を見てください。

Web ベースのアプリケーションで扱うデータ形式がもう 1 つあります。それは
、「クッキー」です。このクッキーもユーザが勝手に値を提供できるので、予
防策を特別に取らない限り信頼できません。また、クッキーはユーザを追跡す
るのによく利用され、ユーザのプライバシーを侵すかもしれません。結果とし
て、ユーザはクッキーを無効にしてしまう場合が多く、Web アプリケーション
はクッキーを必要としないように設計した方が良いでしょう(しかし、個々のユ
ーザを認証しなければいけないとした以前の議論を見てください)。永続するク
ッキー(現在のセッションだけでなく、それ以後も存続するクッキー)の利用を
避けるか、制限をかけることをお薦めします。クッキーは簡単に悪用されてし
まうからです。実際現状では、米国の政府機関は永続するクッキーを特別な例
外を除いて禁止しています。ユーザのプライバシー侵害が心配だからです。 
OMB guidance in memorandum M-00-13 (June 22, 2000) <http://cio.gov/
files/lewfinal062200.pdf> を見てください。クッキーを使用する上で注意し
なければいけないのは、ブラウザの中にはプライバシー・プロファイル(サーバ
のルートディレクトリにある p3p.xml がそれです)を必要とするものがあるか
もしれません。

HTML のフォームにはクライアント側での入力チェックを入れて、これで不正な
値を防御するものがあります。これらは普通、Javascript や ECMAscript、
Java で実装してあります。このチェックは、ユーザにとっては役に立ちます。
ネットワーク経由でアクセスしなくても、「すぐに」チェックができるからで
す。しかし、この種の入力チェックは、セキュリティの点からすると無駄なチ
ェックです。理由は、攻撃者は「不正な」値をチェックを受けずに直接 Web サ
ーバに送りつけられるからです。このチェックを駄目にするのでさえ、難しい
ことではありません。Web アプリケーションに対して、任意のデータを送るよ
うなプログラムを書く必要はありません。一般的には、サーバは入力チェック
をすべて自前で行う必要があります(フォームのデータやクッキー等)。サーバ
は、クライアントがしっかりしているとは信じられないからです。つまり、ク
ライアントは一般的に「信頼に足る伝達経路」ではないからです。信頼できる
伝達経路については、Section 6.11 にさらに情報があります。

Microsoft の Active Server Pages(ASP)を使って入力の妥当性を確認する議論
については、Jerry Connolly 氏が http://heap.nologin.net/aspsec.html で
簡潔に論じています。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.6. その他の入力

プログラムでは、必ず入力すべてをコントロールしてください。しかし setuid
や setgid されたプログラムでは困難を極めます。理由は、そのような入力が
あまりに多いからです。その他の入力プログラムでは、下記の点を考慮する必
要があります。それはカレントディレクトリやシグナル、メモリ・マップ
(mmap)、System V 由来の IPC、 umask(新規にファイルを作成する場合のデフ
ォルトのパーミッションを決定する) についてです。プログラムを起動する時
、ディレクトリを(chdir(2)を使用して)変更する場合は、フルパス指定できち
んと目的のディレクトリに移動することも考慮してください。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.7. 自然言語(ロカール)の選択

コンピュータが増加し、インターネットが身近になるにつれて、プログラムで
複数の言語や文化をサポートすることが強く求められてきています。言語とそ
の他の文化に関連した要素のことを普通「ロカール(locale)」と言います。複
数ロカールに対応するためプログラム修正する過程を「国際化
(internationalization)」(i18n)と呼び、特定のロカール情報をプログラムに
提供することを「地域化(localization)」(l10n)と言います。

全般的には国際化は良いことですが、この過程でセキュリティを侵害する機会
がさらに追加されます。信頼できないユーザが、望ましいロカール情報を提供
できてしまえます。つまり、ロカールを選択する際に、指定したものと異なる
ロカールを入力してしまえます。きちんと防御していなければ、これが悪用さ
れてしまう可能性があります。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.7.1. ロカールを選択するには

ローカルで起動されるプログラム(setuid や setgid したプログラムを含む)で
は、環境変数がロカール情報を提供します。つまり他の環境変数すべてと同じ
ように、使用する前に選択してから、正しいパタンに反していないかチェック
しなければなりません。

Web アプリケーションは、この情報を Web ブラウザから入手します
(Accept-Language 要求ヘッダ経由で)。しかし、ブラウザがすべて正確にこの
情報を渡してくるわけではないので (ユーザすべてがブラウザを正しく設定し
ているわけではないので)、思っているほど役に立ちません。 Web ブラウザが
言語を要求する場合、たいていはただフォームの値として渡すだけです。つま
り、他のフォームの値と同様に、これらの値は使う前に正しいかどうかチェッ
クしなければいけません。

ロカール情報は、どちらのケースにおいても、先のセクションで議論した入力
という意味でまさに特殊なケースです。しかし、この入力はほとんど考慮され
ていないので、あえて独立して論じました。特に書式文字列(後で論じます)と
組み合わさると、ユーザが管理している文字列によって他のプログラムで任意
の命令や不正なデータを動かしたり、その他不適切な動作を攻撃者が実行でき
たりします。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.7.2. ロカールを動かすメカニズム

ロカール・メッセージを選択する方法として、Unix ライクなシステムには大き
く言って 2 つのライブラリ・インタフェースがあります。1 つは「catgets」
、もう 1 つは「gettext」です。 catgets のアプローチは、すべての文字列は
ユニークな番号が割り振られていて、その番号をメッセージが書いてあるテー
ブルのインデックスとして使っています。一方 gettext のアプローチでは、文
字列(通常は英語)を使って、テーブルにある文字列を翻訳したものを捜します
。 catgets(3) は規格として認められていて(X/Open Portability Guide の 3
号と Single Unix Specification で)、プログラムで利用可能です。「gettext
」のインタフェースは、公式の規格ではありませんが(しかしもともとは
UniForum の提案でした)、インタフェースとして catgets より利用されている
と思っています(Sun や GNU のすべてのプログラムで)。【訳註：UniForum に
ついては、 http://www.uniforum.org/ を見てください】 

原理的には catgets の方がわずかに速いはずですが、最近のマシンであればそ
の差はほんのわずかです。また、catgets() が一意の識別子を維持・管理する
のが面倒で、gettext() のインタフェースの方が使いやすくなっています。私
としては、gettext()を使用することをお薦めします。これは使いやすいからに
他なりません。しかし私の言葉をそのまま鵜呑みにしないでください。gettext
については GNU のドキュメント(info:gettext#catgets) で、たっぷりいろい
ろと比較していますので、見てください。

catgets(3)(とそれと関連している catopen(3))はセキュリティ上の問題に対し
てとても脆弱です。それは環境変数である NLSPATH を使用して、国際化された
メッセージを取得するファイル名を管理しているからです。 GNU C ライブラリ
は NLSPATH を setuid や setgid したプログラムでは無視するようになってい
ます。これは役には立ちますが、他の実装で動作するプログラムを防御できま
せんし、そのような防御が必要とは「見えない」その他のプログラム(CGI スク
リプトのような)も防御できません。

広く利用されている「gettext」のインタフェースは、少なくとも私の知る限り
、悪意を持って設定した NLSPATH に対して脆弱ではありません。しかし、悪意
を持って設定した LC_ALL や LC_MESSAGES は、問題を起こすように思えます。
また、gettext の cat-compat.c にある bindtextdomain() ルーチンを使うと
NLSPATH に頼ることになります。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.7.3. 正しい値

とりあえず、信頼できないユーザに希望するロカールを設定させるなら、設定
しようとする国際化情報がフィルタに必ず合致するようにしてください。この
フィルタでは、正しいロカールの名前だけを許可するように限定しておきます
。ユーザ・プログラム(特に setgid や setuid してあるプログラム)は、これ
らの値を次の変数から取得します。それは、NLSPATH や LANGUAGE、LANG、古く
なった LINGUAS、LC_ALL、その他の LC_* (LC_MESSAGES だけでなく、
LC_COLLATE、 LC_CTYPE、LC_MONETARY、LC_NUMERIC、LC_TIME も)です。 Web
アプリケーションでは、ユーザが要求する言語情報は Accept-Language 要求ヘ
ッダもしくはフォームの値として提供されます(アプリケーションは、
Content-Language: ヘッダーを使って、返されるデータの実際の言語設定を示
すべきです)。ユーザがあなたの環境変数を設定していれば(つまり、setgid や
setuid してあるプログラム)、環境変数のフィルタリングの一部もしくは、入
力フィルタ(たとえば CGI スクリプト用に)の一部としてこの値をチェックでき
ます。 GNU の C ライブラリである「glibc」は、setgid や setuid したプロ
グラムでは LANG の値を受け付けないものがありますが(特に「/」を伴ったも
の)、そのフィルタにはエラーがあることがわかっています(たとえば、Red Hat
はこのエラーを修正するために、glibc のアップデートを 2000 年 9 月 1 日
にしています)。この種のフィルタリングは規格上必要とはされていませんので
、あなた自身がフィルタリングを行なうことで、より安全にできます。フィル
タリング言語の設定については、手引きが何も見つけられませんでした。そこ
でここでは、この件について私自身が調査したことに基づいて、アドバイスを
します。

まずは、これらの設定で何が正しい値かについて一言述べておきます。言語設
定は、一般的に IETF RFC 1766 で定義している標準タグを使っています (2 文
字の国コードを基本タグとし、その後に任意でダッシュ(-)で区切ったサブタグ
が続くことがあります。環境変数の場合、アンダースコアを代わりに使います)
。しかし、これは柔軟であるとは言い難く、3 文字の国コードがまもなく利用
できるようになるでしょう。また、機能を拡張したメジャーな 2 つのフォーマ
ットがありますが、互換性があるとはいえません。それは X/Open フォーマッ
トと CEN フォーマット(European Community Standard)です。どちらも許可し
て良いでしょう。典型的な値としては、「C」(C ロカール)や「EN」(英語)、「
FR_fr」(フランスの慣習が生きている地域で利用しているフランス語)がありま
す。また標準ではない名称を使っている場合が多く、プログラムは「別名
(alias)」を使える仕組みを開発する必要にせまられ、標準ではない名称を扱え
るようになりました(GNU の gettext なら /usr/share/locale/locale.alias、
X11 なら /usr/lib/X11/locale/locale.alias を見てください。「alias」では
なく、「aliases 」とする必要があるかもしれません)。どちらも普通は利用で
きるはずです。 gettext()のようなライブラリは、これらのエイリアスをすべ
て受け付けなければならず、できるだけ適切な値を適用できなければいけませ
ん。より詳しい情報は、FSF [1999]や li18nux.org の Web サイトにあります
。フィルタは、不必要な文字を許可すべきではありません。特に「/」(信頼さ
れているディレクトリから抜け出てしまえる可能性がある)や「..」(上位ディ
レクトリに移動できてしまう可能性がある)は許可してはいけません。 NLSPATH
に含まれる他の危険な文字には、「%」(置換を表わす)と「:」(ディレクトリの
区切り)があります。私が所有している他のマシン用資料によると、実装によっ
て、これらの文字が他の値を示すために使われている場合もありますので、禁
止した方が安全である、となっています。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.7.4. 結論

つまり私としては、NLSPATH を削除するか、再設定するかのどちらかを推奨し
ます。そうしないと、その値を渡してくるユーザを信頼しなければいけなくな
ります。 HTTP における Accept-Language ヘッダ(を使うなら)や、ロカールを
指定するフォームの値、上記で挙げた環境変数の LANGUAGE や LANG、古い
LINGUAS、 LC_ALL、その他の LC_* に対しては、信頼できないユーザからのロ
カールに null (値なし)を設定するか、正規表現全体にマッチした値だけを許
可するようにフィルタをかけてください(私は最近このフィルタに「=」を追加
しました)。

 [A-Za-z][A-Za-z0-9_,+@\-\.=]*                                         

正しいロカールで、このパタンにマッチしないものを見たことがありませんが
、このパタンで、ロカールを利用した攻撃を防ぐようです。もちろん、要求さ
れたロカール中に利用できるメッセージが存在する保証はありません。しかし
その場合でも、これらのルーチンはデフォルトのメッセージ(通常は英語) を表
示します。これがセキュリティ上問題とはならないのは確かです。

本当にこだわるなら、代わりに li18nux で提供しているロカールのパタンにマ
ッチするものだけを使ってください。

 ^[A-Za-z]+(_[A-Za-z]+)?                                               
 (\.[A-Z]+(\-[A-Z0-9]+)*)?                                             
 (\@[A-Za-z0-9]+(\=[A-Za-z0-9\-]+)                                     
  (,[A-Za-z0-9]+(\=[A-Za-z0-9\-]+))*)?$                                

どちらの場合も、POSIX の拡張(「新しい」)正規表現の考えに基づいています
(Unix ライクなシステムなら regex(3) や regex(7)を見てください)。

もちろん言語というものは、標準的な手段で書き文字を表現できなくては、言
語をサポートしているとは言えません。このことから文字のエンコードという
問題に直面することになります。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.8. 文字のエンコード

4.8.1. 文字のエンコードとは

長年に渡って、米国では ASCII 文字セットを使って文字のやり取りをしてきま
した。米国のシステムは基本的に ASCII をサポートしているので、簡単に英語
の文字でやり取りできます。残念なことに、その他言語の文字の大半を扱うに
は ASCII ではまったく力不足です。これまでずっと、さまざまな国でいろいろ
なテクニックを使って、さまざまな言語で文字をやり取りしてきました。この
ことが、ますます相互につながりを持ちつつある世界で、データをやり取りす
ることを困難にしています。

つい最近、ISO は ISO 10646 を整備し、「Universal Mulitple-Octet Coded
Character Set(UCS)」としました。 UCS は全世界の文字それぞれに対して、31
ビットの値を定義した符号化文字集合です。 UCS のはじめから 65536 文字(16
ビットに当たります)は、「Basic Multilingual Plane(BMP)」とし、今日使用
されている言語をほぼカバーすることを目的としています。 Unicode コンソシ
アムは Unicode 規格を作成しました。これは UCS に焦点を当て、追加でいく
つか規約を設け、共同で運用できるようにしています。もともと Unicode と
ISO 10646 は競いあって制定を進めてきましたが、ありがたいことに共同して
作業をする必要があることを理解し、今ではお互いに連携しています。

多言語を扱う新規のソフトウェアを書くなら、ISO 10646 や Unicode を基本と
して多言語を扱うようにしてください。しかし、さまざまな(言語固有の)文字
集合で書かれた古いドキュメントを処理する必要があるかもしれませんので、
信頼できないユーザが他のドキュメントの文字集合をコントロールできないこ
とを必ず確認してください。 (ドキュメントの変換処理に影響が大きいからで
す)。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.8.2. UTF-8 とは

ソフトウェアの大半は、16 ビットや 32 ビットの文字を扱うように設計してお
らず、 8 ビット以上が必要な多言語文字集合を作成してもいません。そのため
UTF-8 という特別なフォーマットが開発され、既存のプログラムやライブラリ
が、多言語を表現できる文字列を容易に扱えるような形式にエンコードするこ
ととなりました。 UTF-8 は IETF RFC 2279 で定義してありますので、よくま
とめられた規格が自由に読めて利用ができるのは幸いなことです。 UTF-8 は可
変長でエンコードします。0 から 0x7f(127)の文字は 1 バイトでそのままエン
コードしますが、それより大きな値の文字は 2 から 6 バイトの情報としてエ
ンコードします(値によってバイト数がかわります)。エンコードは、下記の属
性に適合するように特別に設計してあります(これは RFC もしくは Linux に含
まれている utf-8 の man からの情報です)。

 ・ これまで利用していた US ASCII 文字(0 から 0x7f)はそのままエンコード
    しますので、 7 ビットの ASCII 文字だけのファイルや文字列は、ASCII
    でも UTF-8 でも同じエンコードを行います。この方法は、多量にある既存
    の米国製プログラムやデータファイルにとって下位互換性という点で優れ
    ています。
   
 ・ 0x7f より大きい UCS 文字すべてはマルチバイト文字列としてエンコード
    し、 0x80 から 0xfd の範囲に納めます。つまりASCII 文字を他の文字の
    一部として表現することはありません。他のエンコード方法では NIL のよ
    うな文字を組み込めるので、プログラムが処理できなくなってしまいます
    。
   
 ・ UTF-8 と 2 バイトもしくは 4 バイト固定長の文字表現間の変換は簡単に
    できます(それぞれ UCS-2 及び UCS-4 と呼ばれます)。
   
 ・ UCS-4 文字列での辞書順ソートの並びはそのままなので、Boyer-Moore 法
    による高速検索アルゴリズムが UTF-8 のデータにも直接利用できます。
   
 ・ 2^31 ビットのすべての UCS コードが UTF-8 を使用してエンコードできま
    す。
   
 ・ あるマルチバイト文字列の先頭のバイトが ASCII 文字ではない場合、その
    値の範囲は常に 0xc0 から 0xfd になり、そのマルチバイト文字列長がど
    のくらいなのかを示しています。残りすべては 0x80 から 0xbf の範囲に
    なります。これで簡単に同期を取り直せます。つまりあるバイトが落ちて
    しまっても、スキップすることで簡単に「次」の文字に進めますし、「前
    後」の文字にも簡単に行きつ戻りつできます。
   
要するに UTF-8 の変換フォーマットは、多言語のテキスト情報をやりとりする
のに秀でており、世界中のあらゆる言語をサポートできます。その上なお、US
ASCII ファイルと下位互換性があると同時に、他の優れた属性も持っています
。いろいろな目的に採用することをお薦めします。「テキスト」ファイルにデ
ータを保存する場合にはなおさら。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.8.3. UTF-8 のセキュリティ上の課題

UTF-8 に言及する訳は、バイト列に不正な UTF-8 があると、それがセキュリテ
ィホールになるかもしれないからです。 UTF-8 は、「最短」エンコードの利用
を想定していますので、そのままデコードすると、必要以上に長い文字列をエ
ンコードしたものを受けてしまうかもしれないからです。実際、初期の規格で
は「最短」でないエンコードを認めていました。ここで問題となるのは、複数
の方法で危険な入力が行われる可能性があり、そのことによって、危険な入力
に対するセキュリティ処理が無になるかもしれないということです。 RFC では
その問題を下記のように記載しています。

   
    UTF-8 の実装では、不正な UTF-8 文字列をどのように対処するか、という
    セキュリティ上の観点を考慮する必要があります。環境によっては、攻撃
    者が無防備な UTF-8 パーサに UTF-8 の文法では認められていないオクテ
    ット文字列を送りこみ、悪用してしまうことも考えられます。
   
    この攻撃は、入力に対してセキュリティに重点をおいた正当性チェックを
    行うパーサに対して、実に巧妙に実行されます。UTF-8 でエンコードして
    あるものの、文字として不正なオクテット列として解釈されてしまう入力
    がそれに当たります。たとえば、パーサは 00 という単独のオクテット文
    字がエンコードされた場合には NULL 文字を禁止しているかもしれません
    。しかし不正であるオクテット文字 2 文字である C0 80(必要以上に長い)
    は許しており、それを NUL 文字(00)として処理しています。その他の例と
    しては、オクテット文字列である 2F 2E 2E 2F ("/../")は禁止しています
    が、不正である 2F C0 AE 2E 2F は許してしまっています。
   
 

この件についてのさらなる論議は Markus Kuhn 氏のサイト http://
www.cl.cam.ac.uk/~mgk25/unicode.html にある UTF-8 and Unicode FAQ for
Unix/Linux で読めます。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.8.4. UTF-8 の正しい値

つまり、UTF-8 を入力として受け付ける場合は、その入力が正しい UTF-8 なの
かをチェックする必要があります。ここで挙げる一覧は、正しい UTF-8 文字列
すべてです。文字がこのテーブルにマッチしなければ、正しいとは言えません
。下記のテーブルで 1 番目のカラムは UTF-8 にエンコードする各種文字コー
ドです。 2 番目は文字がどのようにバイナリにエンコードするかを示していま
す。「x」はデータがあること(0 か 1)を示しますが、最短エンコードでない場
合には認めるべきでないケースもあります。最後は、それぞれのバイトが取り
うる正しい値(16 進表示)です。したがって、個々の文字が右側のカラムのパタ
ンのどれに当てはまるのか、プログラムでチェックする必要があります。「-」
は正しい値の範囲(両端を含む)を表わしています。もちろん、文字列が正しい
UTF-8 の文字列であると言うことだけで、受け入れて良いとは言えませんが(そ
の他のチェックも必要)、普通、他のチェックをする前に UTF-8 の正当性をチ
ェックする必要があります。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

Table 4-1. Legal UTF-8 Sequences

┌──────────┬───────────┬──────────┐
│UCS Code (Hex)      │Binary UTF-8 Format   │Legal UTF-8 Values  │
│                    │                      │(Hex)               │
├──────────┼───────────┼──────────┤
│00-7F               │0xxxxxxx              │00-7F               │
├──────────┼───────────┼──────────┤
│80-7FF              │110xxxxx 10xxxxxx     │C2-DF 80-BF         │
├──────────┼───────────┼──────────┤
│800-FFF             │1110xxxx 10xxxxxx     │E0 A0*-BF 80-BF     │
│                    │10xxxxxx              │                    │
├──────────┼───────────┼──────────┤
│1000-FFFF           │1110xxxx 10xxxxxx     │E1-EF 80-BF 80-BF   │
│                    │10xxxxxx              │                    │
├──────────┼───────────┼──────────┤
│10000-3FFFF         │11110xxx 10xxxxxx     │F0 90*-BF 80-BF     │
│                    │10xxxxxx 10xxxxxx     │80-BF               │
├──────────┼───────────┼──────────┤
│40000-FFFFFF        │11110xxx 10xxxxxx     │F1-F3 80-BF 80-BF   │
│                    │10xxxxxx 10xxxxxx     │80-BF               │
├──────────┼───────────┼──────────┤
│40000-FFFFFF        │11110xxx 10xxxxxx     │F1-F3 80-BF 80-BF   │
│                    │10xxxxxx 10xxxxxx     │80-BF               │
├──────────┼───────────┼──────────┤
│100000-10FFFFF      │11110xxx 10xxxxxx     │F4 80-8F* 80-BF     │
│                    │10xxxxxx 10xxxxxx     │80-BF               │
├──────────┼───────────┼──────────┤
│200000-3FFFFFF      │111110xx 10xxxxxx     │too large; see below│
│                    │10xxxxxx 10xxxxxx     │                    │
│                    │10xxxxxx              │                    │
├──────────┼───────────┼──────────┤
│04000000-7FFFFFFF   │1111110x 10xxxxxx     │too large; see below│
│                    │10xxxxxx 10xxxxxx     │                    │
│                    │10xxxxxx 10xxxxxx     │                    │
└──────────┴───────────┴──────────┘
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

先に触れたように、文字集合には ISO 10646、Unicode という 2 つの規格があ
りますが、文字の割り当てに関しては同期を取っています。現状、ISO/IEC
10646-1:2000 と IETF RFC における UTF-8 の定義では、5、6 バイト文字列の
エンコードもサポートしており、文字を Uniforum の Unicode の範囲外にエン
コードしています。しかしそのような値は、Unicode 文字としてはサポートさ
れてこなかったので、ISO 10646 の将来のバージョンでも同様の制約を受ける
と思われます。つまり、5、6 バイトの UTF-8 のエンコードが正しいケースは
ほとんど無く、通常は拒否しなければいけません(特別な目的が無い限り)。

正しい値の範囲を特定するのは困難です。そして実際このドキュメントの初期
の版では、間違った項目がいくつか記載してありました(長すぎる文字を許して
しまっているケースがありました)。言語開発者は、ライブラリに正しい UTF-8
の値をチェックする機能を入れる必要があります。チェックを正しく行うのは
とても困難なので。

場合によって、16 進の C0 80 に対して、それほどシビアにしたくない(もしく
は内部で何とかしたい)ケースがあるかもしれない、という点を示しておきます
。これは長すぎる文字列で、許可してしまうと ASCII の NUL(NIL)に相当する
ことになります。C と C++ では NIL 文字を通常の文字列に入れてしまうとや
っかいなことになりますので、データストリームの一部として NIL を表したい
時に、この並びを用いるケースがあります。Java ではこの操作を正式に記載し
ています。データ処理を行う時に、内部的には C0 80 を好きに扱ってください
。ただし、厳密に言うと、そのデータを保存する前に 00 に変換し直す必要が
あります。必要性にもよりますが、「シビアにならずに」、C0 80 を UTF-8 の
データストリームとして認めてもよいかもしれません。セキュリティに影響が
でないなら、運用を助けるという観点で許可するのはよい案だと思います。

この対処は微妙です。 Unicode フォーラムで開発した C による変換ルーチン
を調査したいなら、 ftp://ftp.unicode.org/Public/PROGRAMS/CVTUTF/
ConvertUTF.c を利用してみてはどうでしょうか。このルーチンがオープンソー
スかどうかはっきりしませんので(ライセンスを読んでも、修正可能かどうかわ
かりません)、その点は注意してください。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.8.5. UTF-8 関連について

このセクションでは UTF-8 を論じます。UCS で多バイトをエンコードするのに
最も一般的で、各種の国際化テキストが抱える問題を簡単に扱えるからです。
しかし、それだけがエンコードでないのも事実です。他のエンコードとして
UTF-16 や UTF-7 のようなエンコードがあり、同様な問題を抱えていますので
、同じような理由で検証しなければいけません。

もう 1 つの問題として、複数の表現法で表せるものが ISO 10646 や Unicode
にある点です。たとえば、アクセント文字の中には 1 文字(アクセント付き)で
表現できるものがありますが、文字の組み合わせ(たとえば、ベースになる文字
にアクセントをのせる) で表現できるものもあります。この 2 つの形式は、同
一であるかもしれません。幅がないスペースを挿入した結果、異なるものが見
た目同じように見えることもあります。そのような隠れたテキストが存在する
状況において、プログラムに影響が出る点に注意を払ってください。これは一
筋縄では行かない問題です。プログラムは、特定の文字列をどのように表示す
るのかを完全に掌握しているクライアントに対して、そのようなきつい制約を
かけていない場合が大半です(クライアントのフォントや表示特性、ロカール等
に依存しているので)。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.9. サイトにまたがった悪意あるコンテンツ(Cross-site Malicious Content)
を防ぐ

信頼できないユーザからのデータを受け付けて、そのデータを次のユーザに渡
すプログラムもあります。二番目のユーザのアプリケーションが、見方によっ
てはそのユーザにとって迷惑になる処理をするかもしれません。これは Web ア
プリケーションではありがちな問題です。この問題をサイトにまたがった悪意
あるコンテンツ(Cross-site Malicious Content)と呼ぶことにします。つまり
、入力(フォームデータも含む)を必ずチェックして、フィルタをかけるか、エ
ンコードするかしないといけません。詳しい情報は、Section 6.15 を見てくだ
さい。

原則として、Web アプリケーションへの入力はすべて、フィルタをかけたり(こ
の問題を起こす文字を削除する)、エンコードしたり(この問題を起こす文字が
問題を起こさないようにエンコードする)、検証したり(確実に「安全な」デー
タだけが通過するようにする)しなければいけないことを意味します。フィルタ
リングや検証は、入力時に終わらせた方が良いのが普通ですが、エンコードは
入力時でも出力時でも済ませられます。分析をせずにデータを通してしまうな
ら、入力時にデータをエンコードする方が良いと思います(忘れないでしょうか
ら)。しかしデータを処理しているなら、エンコードを入力時ではなく出力時に
する点については、まだどちらがよいか結論が出ていません。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.10. 再表示する可能性のある HTML や URI にはフィルタをかける

サイトにまたがった悪意あるコンテンツ(Cross-site Malicious Content)を防
がなければならない特徴的なケースの 1 つに、Web アプリケーションが挙げら
れます。その Web アプリケーションは、あるユーザから HTML や XHTML を受
け取り、それを他のユーザに渡すように設計してあります(詳しい情報は 
Section 6.15 を見てください)。下記のサブセクションでは、特にこの種の入
力のフィルタリングについて論じます。そういうケースを扱う必要性が当たり
前になってきたからです。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.10.1. HTML データを削除したり禁じたりする

(X)HTML タグをできるだけ削除すれば、最も安全になります。そうすれば、タ
グによる影響は何も起こらず、また実現するのも比較的簡単です。以前指摘し
たように、正しい文字の一覧を確認しているはずですから、その一覧にない文
字を拒否したり、削除したりできるはずです。正しい文字の一覧に載っている
からといって、単純にこのフィルタへ次の文字を入れてはいけません。その文
字とは「<」や「>」、「&」(属性に使うなら二重引用符の「"」も)です。ブラ
ウザが HTML の仕様に従って動作するだけなら、「>」は削除する必要はありま
せん。しかし、実際は削除しなければいけません。理由は、開始を示す「<」を
そのページの著者が本当は置きたかった、と推測しているブラウザがあるから
です。この「手助け」が、攻撃者につけ込む余地を与えて、「>」を使って「
<」という望ましくない文字を作ってしまいます。 

文字集合を HTML で送るには、通常 ISO-8859-1(国際化テキストを送る時でさ
え) を使います。したがってフィルタは制御文字(改行やタブは普通は OK)のほ
とんどとハイビットにある文字も削除するべきです。

このやり方で問題になるものの 1 つは、国際化テキストを入力したユーザがそ
のテキストが知らない内に消されてしまい、びっくりするという点です。無効
な文字が何の警告もなく削除されると、そのデータは完全になくなり、後にな
って再構成のしようがありません。選択肢の 1 つとして、そのような文字を禁
止した上で、文字を使おうとしたユーザにエラーメッセージを送り返してあげ
る方法があります。少なくともこれでユーザに警告を出せますが、ユーザが望
んでいる機能を提供できるわけではありません。その他には、そのデータをエ
ンコードする方法と検証する方法が挙げられます。これについては次に議論し
ます。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.10.2. HTML データをエンコードする

他にほぼ安全な方法として、危険な文字を変換してしまい、HTML 上で意味を無
くす、というものがあります。すべての「<」を「&lt;」に、「>」を「&gt;」
に、「&」を「&amp;」にしてしまえばお終いです。国際化文字ならどれも「&#
value;」という形式を使って、Latin-1 にエンコードできます。最後のセミコ
ロンを忘れないでください。当然、入力エンコードをどうするかを理解してい
なければいければ、国際化文字のエンコードはできません。

ここで考えられる危険には、エンコードした結果をたまたま 2 回処理すると脆
弱さが生まれてしまう、という現象が挙げられます。しかしこのやり方では、
少なくとも入力の「目的」が何であるのかを受けとったユーザに伝えられます
。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.10.3. HTML データを検証する

アプリケーションがすべて機能する過程で、HTML を第三者から受け付けなけれ
ばならず、その受け付けた内容を別のユーザに対して送る場合があります。こ
れは用心しなければいけません。今あなたは、とても危ない橋を渡っています
。本当にこうすることが必要なのか、自問自答してください。あらゆるところ
から HTML を受け入れる、という考えでさえ、セキュリティに精通した人々の
間では賛否両論です。なぜなら、正しく取得するのは極めて困難だからです。

しかし、アプリケーションで HTML を受けざるを得ず、リスクを負うだけの価
値があると思うのなら、少なくとも HTML の「安全な」コマンドの一覧を確認
してから、そのコマンドだけを許可するようにしてください。

安全な HTML タグでアプリケーション(ゲストブックのような)にとって役に立
つものを最低限ここにあげました。簡単なコメントをつけてあります。 <p>
(パラグラフ)、 <b> (ボールド)、 <i> (イタリック)、 <em> (強調)、
<strong> (さらに強調)、 <pre> (事前に整形してあるテキスト), <br> (強制
改行。閉じ用のタグは必要ありません) 上記に対応して終了タグもあります。

少数の「安全な」HTML コマンド群だけを受け入れるだけではなく、それらが入
れ子になって閉じている(つまり、HTML コマンドが「対応がとれている」) よ
うに必ずしてください。 XML では、これを「整形式(well-formed)」データと
呼んでいます。標準 HTML を許しているなら、多少例外があるでしょう(たとえ
ば、<p> が出てくる前のところに </p> を想定するのは問題ないと思います)。
しかし、HTML ができる表現すべて(対応をとるための閉じ用タグが推測できる
場合が多い)を受け入れようとするのは、アプリケーション大半にとって必要で
はありません。もっとはっきり言うと、XHTML(HTML のかわりに) に忠実であろ
うとするなら、整形が必要条件です。また、HTML タグは大文字、小文字を区別
しません。タグは大文字でも、小文字でも、混ぜて使ってもかまいません。し
かし、XHTML を受け入れるつもりなら、タグはすべて小文字にしなければいけ
ません(XML は大文字、小文字を区別します。XHTML は XML を使い、タグが小
文字であることが必要です)。

ここでいくつか TIPS を順不同であげておきます。通常は、HTML テキスト及び
許可すべきタグの集合に関する何かしらの設計を行なった方が良いでしょう。
そうすれば、投稿されたテキストが「メイン」サイトのテキストとして誤って
処理されなくなります(偽造を防ぎます)。どんな属性も、その属性タイプや値
をチェックすることなしに受け入れてはいけません。 Javascript のように、
ユーザをトラブルに巻き込む恐れがある属性がたくさんあります。それらの属
性をサポートする必要があります。上記の一覧には、属性がまったく存在しな
いことに注目してください。これが安全、確実な方法なのです。安全ではない
タグが使われたなら、おそらく警告メッセージを出した方が良いでしょう。し
かしこれが現実的でないなら、危険な文字をエンコードして(たとえば「<」を
「&lt;」にする)、ユーザの安全を維持しつつ、データがなくなることは防いで
ください。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.10.4. ハイパーテキストリンク(URI や URL)を検証する

注意深い方ならお気づきだと思いますが、ハイパーテキストのリンクタグ <a>
を安全な HTML タグとはしていません。明らかに、<a href="safe uri">(ハイ
パーテキストリンク)を安全な一覧に追加できたのにもかかわらずです(内容を
チェックしない限り、他のどの属性も許可しないこと)。アプリケーションが必
要としているなら、追加してもかまいません。しかし第三者がリンクを張るこ
とで、安全性がさらに低下します。理由は、「安全な URI」の定義にあります
。[1] これが結果的にはとても面倒事になります。多くのブラウザは、ユーザ
にとって危険かもしれないあらゆる URI をすべて受け取ってしまうからです。
このセクションでは、第三者からやって来て、他の人に再表示する URI の検証
方法と、その URI を HTML にどのように組み込むかについて論じます。

まず URI の文法をざっと見て行きましょう(さまざまな仕様書で定義してある
ので)。 URI は「絶対」も「相対」も可能です。絶対 URI はこのようになりま
す。

scheme://authority[path][?query][#fragment]                            

URI はスキーム名(「http」のような)からはじまり、「://」、責任者部
(authority)、 (「www.dwheeler.com」のように)、パス(ディレクトリ名やファ
イル名のような) と続きます。この後に疑問符を置いてクエリが続いたり、ハ
ッシュ(「#」)を置いてフラグメント識別子が続いたりします。オプション部分
は [] で囲んであります。ただ現実には、クエリやフラグメントを含む URI は
多くはありません。スキームには、許可しないデータ(たとえばパスやクエリ、
フラグメント)がある一方、固有の条件を追加する場合もたくさんあります。ス
キームは「責任者部」にオプションでユーザ名やパスワード、ポート番号を許
可している場合がよくあります。書き方は次の通りです。

 [username[:password]@]host[:portnumber]                               

「host」は名前(「www.dwheeler.com」)か IPv4 の数値形式のアドレス
(127.0.0.1) を指定できます。「相対」URI はあるオブジェクトを「現在の」
オブジェクトからの相対位置で参照し、その書き方はファイル名にとてもよく
似ています。

path[?query][#fragment]                                                

たいていの URI では、許可している文字数に制限があり、この問題を回避する
ために 8 ビット文字を「URL エンコード」して %hh(hh には 8 ビット文字が
16 進の値で入ります) とします。正しい URI について、さらに詳しい情報は
IETF RFC 2396 とそれに関連した規格書を見てください。

ここまで URI の書き方を見てきましたので、こんどはそれぞれの部分が持つ危
険性を調べてみましょう。

 ・ スキーム：スキームの大部分は実に危険です。「javascript」を含むスキ
    ームを挿入できるようにしてしまうと、ちょっとしたサービス拒否攻撃を
    実装することになってしまいます(たとえば、ウインドウ作成を繰り返すこ
    とで、ユーザのマシンがフリーズして、利用できなくなります)。もっと深
    刻なのは、javascript の実装にある既知の脆弱性を攻撃される恐れがある
    点です。スキームには「mailto:」のように、メールを出すつもりがなくて
    も出してしまう困ったものや、クライアントマシンで十分に安全が確保で
    きないものもあります。つまり、少数の安全なスキームだけに限定して、
    スキームを許可する必要があります。
   
 ・ 責任者部：欲を言えば、ユーザには「安全な」サイトへのリンクだけを許
    可した方が良いでしょう。しかしそれは現実的にとても困難です。しかし
    、ユーザ名やパスワード、ポート番号に対して何か手を打たなければいけ
    ません。禁止すべきなのです。ユーザ名(とりわけパスワードをともなっ
    た)を必要としているシステムはおそらくより重要な情報をガードしていま
    す。誰でもポストできる URI では、ほとんどこの機能は必要ではありませ
    ん。またユーザがアクセスした情報を見せたり、ユーザが情報を修正した
    りするのをユーザに分かってもらうために、この機能を利用しているとこ
    ろもあります。このような URI では、セマンティック攻撃(semantic
    attack)が可能になります。詳しくは、Section 6.16 を見て下さい。パス
    ワード無しのユーザ名もやはり危険です。ブラウザはたいてい、パスワー
    ドをキャッシュするからです。通常は、ポート指定はすべきではありませ
    ん。理由は、ポートが異なれば、プロトコルも異なることを期待して、結
    果的に「プロトコルの混乱」で攻撃の隙を与えるからです。たとえば、あ
    るシステムでは「gopher」スキームが利用可能で、SMTP(電子メール) ポー
    トを指定することで、あるユーザに攻撃者が送りたいメールを送らせられ
    ます。特殊なケース(たとえば http ポートを 8008 や 8080 とする)は認
    めてもよいかもしれませんが、全体的に見ると、そうするだけの価値はあ
    りません。ホストを名前で指定する場合に、かなり文字集合に制限があり
    ます(DNS の仕様を使うと)。技術的に言うと、仕様ではアンダースコア(「
    _」)を認めていませんが、Microsoft はこの仕様の部分を無視しているだ
    けでなく、ある環境ではアンダースコアの使用を必要とさえしています。
    したがっておそらく認めざるを得ないケースがあるでしょう。また DNS 名
    で多言語をサポートする作業に精力をつぎ込んでいますが、ここではこれ
    以上は論じません。
   
 ・ パス：普通、パスを許可して問題ありませんが、残念ながらパスの一部を
    クエリとして使って、穴を空けてしまうアプリケーションがあります。こ
    れについては次で論じます。また、パスに「..」と同種の書式を設定でき
    ますので、いい加減な実装をしている Web サーバでは、プライベートなデ
    ータをさらしかねません。これは、以前ほど問題ではなくなっているので
    、Web サーバ側できちんと修正してください。「..」という書式だけは特
    別で、パス(できればクエリも)見て、「../」を設定できないようにしてく
    ださい。しかし、検証する仕組みが URL エスケープを許可していると、こ
    れは難しくなるでしょう。そこで必要になるのは、これらの文字をエスケ
    ープしているバージョンを避け、かつ、これらの文字に対するさまざまな
    「不正」エンコードをうまく扱うようにしなければならないことです。
   
 ・ クエリ：クエリのフォーマット(「?」ではじまる)がセキュリティ上のリス
    クになるかもしれません。というのも、クエリのフォーマットには、実際
    はクライアント側で動作を起こすものがあるからです。そうあってはいけ
    ないし、あなたのアプリケーションも同様です。この件については 
    Section 4.11 に詳しい情報があります。しかし重大な問題として、事実を
    直視する必要があります。加えて、Web サイトの多くは、現実には「リダ
    イレクトを提供する場所」です。リダイレクトするには、ユーザが向かう
    べきところを特定できるパラメタを取得し、ユーザに新しい場所へリダイ
    レクトするコマンドを送り返します。攻撃者がそのようなサイトを参考に
    して、さらに危険な URI にリダイレクトする値を提供し、その値でブラウ
    ザが軽率にリダイレクトしてしまうと、これは問題になります。繰り返し
    になりますが、ブラウザにはもっと注意を払ってください。しかし、十分
    な注意をユーザがすべて払っているわけではありません。また、Web アプ
    リケーションには脆弱さがある場合が多く、あるクエリ値で攻撃を受けて
    しまう可能性があります。しかしこれを防ぐのは困難です。公式な URI の
    規格では、「+」(プラス)文字を認めていませんが、現実には「+」文字は
    スペース文字を表わすのによく使われています。
   
 ・ フラグメント：フラグメントはそもそもドキュメントの一部です。文法が
    正しいならば、フラグメントに対する攻撃はないと思っていましたが、そ
    の文法の正当さ自体をチェックする必要があります。それでも攻撃者は、
    二重引用符(")のような文字を入れたり、中途半端に URI を終わらせたり
    できるかもしれません(チェックの裏をかいて)。
   
 ・ URL エスケープ： URL エスケープは便利です。というのは、どんな 8 ビ
    ット文字も表現できるからです。しかし同時にとても危険であり、それに
    は訳があります。特に、URL エスケープは制御文字が表現でき、出来の良
    くない Web アプリケーションの多くがこの表現に対して無防備です。実際
    には URL エスケープがあろうがなかろうが、Web アプリケーションはある
    文字に対して無防備です(バックスラッシュやアンパサンド等)。しかしこ
    れもやはり一般化するのが困難です。
   
 ・ 相対 URI：相対 URI はかなり安全なはずですが(Web サイトをうまく運営
    していれば)、アプリケーション次第で、相対 URI を許可しない方がよい
    ものもあります。
   
もちろん、単純さとのトレードオフもあります。単純なパタンは理解しやすい
のですが、正確だとは言えません(単純であるがゆえにあまりに甘いか、あまり
にきついかのどちらかです。それが正確なパタンであったとしても)。複雑なパ
タンはより正確になり得ますが、さらにエラーが起こったり、より性能が必要
となったりする恐れがあります。また環境によっては、実行するのが困難な場
合もありえます。

ここでは私の案として、「単純かつほとんど安全な」URI パタンを紹介します
。これは「手作業」で実行できる程単純で、正規表現を使っても可能です。下
記が許可するパタンです。

(http|ftp|https)://[-A-Za-z0-9._/]+                                    

このパタンは潜在的に危険となる可能性のあるようなクエリやフラグメント、
ポート、相対 URI 等を認めず、わずかなスキームだけしか許可していません。
これは「%」文字の使用を防ぐことで、URL エスケープを避け、サーバがうまく
扱えないかもしれない文字を特定できるようになります。また「:」や URL エ
スケープも許可していないので、ポートを指定するのも認めていませし、より
危険な URI へのリダイレクトも困難になります(エスケープ文字が抜けている
ため)。またその他多くの文字の利用も防ぎます。繰り返しますが、出来の良く
ない Web アプリケーションは「予想外の」文字をうまく扱えません。

この「ほとんど安全な」URI でさえ、疑わしい URI をいろいろと許可してしま
います。疑わしいものとは、サブディレクトリ(「/」を利用して)や上位ディレ
クトリへの移動 (「..」を利用して)を試みるようなものです。この手の不正な
クエリは、サーバが検知すべきです。不正なホスト ID(たとえば「20.20」)は
許可してしまいますが、これがセキュリティ上の弱点となったケースを私は知
りません。 Web アプリケーションには、サブディレクトリをクエリのデータ
(もっとひどいものだと、コマンドのデータ)として扱うものもあります。これ
を防ぐのは一般的に困難です。というのも、「お粗末な設計の Web アプリケー
ションすべて」を見つけられる見込みは皆無だからです。パスの使用制限は可
能ですが、そうしてしまうとインターネット上の情報をほとんど参照できなく
なってしまいます。またこのパタンでは、ローカルなサーバ上の情報(「http:/
//」や「http://localhost/」、「http://127.0.0.1」を使って)は参照可能で
、マシンの内部ネットワークを使ってサーバにアクセスしています。ここでは
サーバが、HTTP の GET 命令の結果を何かを動かす命令ではなく、単に情報を
取得する、という正しい解釈をするという前提に立たなければなりません。 
Section 4.11 でこの点を推奨しています。このパタンではクエリの書式を認め
ていませんので、ほんとんどの環境ではこれで十分なはずです。

残念ながら、「ほとんど安全な」パタンが、まともで役に立つ URI も数多く防
いでしまいます。たとえば、Web サイトの多くは、「?」文字を特定のドキュメ
ントを区別するのに使用しています(たとえば news サイトでの記事)。「#」文
字はドキュメント中の特定のセクションを特定するのに役に立ちますし、相対
URI を許可することで、議論が扱い易くなります。さまざまな許可された文字
や URL エスケープは「ほとんど安全な」パタンには含まれていません。たとえ
ば、URL エスケープを許可しないと、英語以外のページにアクセスするのは困
難になります。本当にそのような機能が必要なら、機能が上がるほどユーザの
リスクも増えるということを認識した上で、安全性が低いパタンを使ってもか
まいません。

クエリは許可するが、プロトコルやポートに制限をかけるパタンは下記の通り
です。私はこれを「単純でやや安全なパタン」と呼ぶことにします。

 (http|ftp|https)://[-A-Za-z0-9._]+(\/([A-Za-z0-9\-\_\.\!\~\*\'\(\)\%\?]+))*/?

このパタンは洗練されているわけではありません。不正なエスケープや複数の
クエリ、 ftp でのクエリ等を認めているからです。ただ比較的単純という長所
は持っています。

現実には、「やや安全な」パタンの作成して、正しい値を持つ URI を制限する
のは非常に難しい作業です。ここでは、現状私が試しているパタンである「手
の込んだやや安全なパタン」を載せてみます。空白は無視して、コメントは「#
」で表示してあります。

 (                                                                              
 (                                                                              
  # Handle http, https, and relative URIs:                                      
  ((https?://([A-Za-z0-9][A-Za-z0-9\-]*(\.[A-Za-z0-9][A-Za-z0-9\-]*)*\.?))|     
    ([A-Za-z0-9\-\_\.\!\~\*\'\(\)]|(%[2-9A-Fa-f][0-9a-fA-F]))+)?                
  ((/([A-Za-z0-9\-\_\.\!\~\*\'\(\)]|(%[2-9A-Fa-f][0-9a-fA-F]))+)*/?) # path     
   (\?(                                                              # query:   
       (([A-Za-z0-9\-\_\.\!\~\*\'\(\)\+]|(%[2-9A-Fa-f][0-9a-fA-F]))+=           
        ([A-Za-z0-9\-\_\.\!\~\*\'\(\)\+]|(%[2-9A-Fa-f][0-9a-fA-F]))+            
        (\&([A-Za-z0-9\-\_\.\!\~\*\'\(\)\+]|(%[2-9A-Fa-f][0-9a-fA-F]))+=        
         ([A-Za-z0-9\-\_\.\!\~\*\'\(\)\+]|(%[2-9A-Fa-f][0-9a-fA-F]))+)*)        
       |                                                                        
       (([A-Za-z0-9\-\_\.\!\~\*\'\(\)\+]|(%[2-9A-Fa-f][0-9a-fA-F]))+  # isindex 
       )                                                                        
   ))?                                                                          
   (\#([A-Za-z0-9\-\_\.\!\~\*\'\(\)\+]|(%[2-9A-Fa-f][0-9a-fA-F]))+)? # fragment 
  )|                                                                            
 # Handle ftp:                                                                  
 (ftp://([A-Za-z0-9][A-Za-z0-9\-]*(\.[A-Za-z0-9][A-Za-z0-9\-]*)*\.?)            
  ((/([A-Za-z0-9\-\_\.\!\~\*\'\(\)]|(%[2-9A-Fa-f][0-9a-fA-F]))+)*/?) # path     
  (\#([A-Za-z0-9\-\_\.\!\~\*\'\(\)\+]|(%[2-9A-Fa-f][0-9a-fA-F]))+)? # fragment  
  )                                                                             
 )                                                                              

 

上記の手の込んだパタンでも、不正な URI すべてを禁止するわけではありませ
ん。たとえば、繰り返しになりますが「20.20」は不正なドメイン名ですが、パ
タンを通過してしまいます。しかし私の知るところでは、これによってセキュ
リティ上の問題は発生しません。手の込んだパタンは制御文字(たとえば %00
から %FF の範囲)を表す URL エスケープを禁止しています。許可している最小
のエスケープ値は、%20(ASCII の空白) です。制御文字を禁止することで、ト
ラブルはいくつか防げますが、制約もあります。すべての「2-9」を「0-9」に
変更することで、制御文字を任意の Web アプリケーションに送れるようになり
ます。このパタンはパスにおいて、これ以外すべての URL エスケープを許可し
ています。国際化文字には便利ですが、国際化文字を扱えないシステムでは問
題を起こします。このパタンは少なくとも URI の中で、空白や改行、二重引用
符、その他危ない文字を防ぎます。これによって、その URI を作成済みのドキ
ュメントに組み込んだ時にその他の種類の攻撃を防ぎます。このパタンはあち
こちで「+」を許可している点に注意してください。理由は、プラスが現実には
空白文字の代わりとして、クエリやフラグメントで使われているからです。

上記で述べたように、残念なことにクエリデータを許可すると、そのテクニッ
クを使った攻撃があり、またクエリを許可してしまうと、現実に防御がほうま
くできないように思えます。そこで、上記のパタンからクエリデータを扱う機
能を除いてしまうことも、やろうと思えば可能です。やり方を変えて「手の込
んだやや安全なパタン」を作成してみます。

 (                                                                              
 (                                                                              
  # Handle http, https, and relative URIs:                                      
  ((https?://([A-Za-z0-9][A-Za-z0-9\-]*(\.[A-Za-z0-9][A-Za-z0-9\-]*)*\.?))|     
    ([A-Za-z0-9\-\_\.\!\~\*\'\(\)]|(%[2-9A-Fa-f][0-9a-fA-F]))+)?                
  ((/([A-Za-z0-9\-\_\.\!\~\*\'\(\)]|(%[2-9A-Fa-f][0-9a-fA-F]))+)*/?) # path     
   (\#([A-Za-z0-9\-\_\.\!\~\*\'\(\)\+]|(%[2-9A-Fa-f][0-9a-fA-F]))+)? # fragment 
  )|                                                                            
 # Handle ftp:                                                                  
 (ftp://([A-Za-z0-9][A-Za-z0-9\-]*(\.[A-Za-z0-9][A-Za-z0-9\-]*)*\.?)            
  ((/([A-Za-z0-9\-\_\.\!\~\*\'\(\)]|(%[2-9A-Fa-f][0-9a-fA-F]))+)*/?) # path     
  (\#([A-Za-z0-9\-\_\.\!\~\*\'\(\)\+]|(%[2-9A-Fa-f][0-9a-fA-F]))+)? # fragment  
  )                                                                             
 )                                                                              

今言えることは、これらのパタンがユーザが選択したハイパーテキストのアン
カー (「<a>」タグ)だけをチェックしている限り、この方法で「Web のバグ」
の混入も防ぎます。 Web バグは単純なテキストで、メインページのある大元の
Web サーバではない第三者が、いつ誰がそのコンテンツを読んだか、というよ
うな情報を追跡できるようにします。詳しい情報は、 Section 7.7 を見てくだ
さい。同じようなチェックルールで <img>(画像)タグに使っているなら、これ
は当てはまりません。画像タグは即座にロードされ、誰かが「Web バグ」を追
加できます。くどいようですが、ここではどんな属性も許可していない、とい
うことを前提にしています。危険な属性はとても多く、せっかく提供しようと
しているセキュリティに穴をあけてしまいます。

これらすべてのパタンは、URI がそのパタンに完全にマッチしていることが条
件になっていることをどうか忘れないでください。このパタンで不満なところ
は、ある面、許容可能なパタンにも制限をかけてしまい、便利なパタンの多く
を禁じてしまうところです(たとえば新たな URI スキームの利用を妨げます)。
また、Web サイトの中には 1 つのクエリを表わすのに、さらに多くのクエリが
実行されるところもあり、これを防ぐのは現実問題としてとても困難です。さ
らにそのような Web サイトには、全体構成に組み込まれてしまっているものも
あります。結果として、Web サイトが複数の GET クエリを 1 つの動作として
受け取る限りは、 URI は本当に安全とは言えません(Section 4.11 参照)。正
しい URL や URI についてさらに情報が知りたければ、IETF RFC 2396 を見て
ください。ドメイン名の書式については、IETF RFC 1034 で詳しく論じていま
す。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.10.5. その他の HTML タグ

さらに HTML タグをサポートするにはどうしたら、と考えても不思議はありま
せん。次に打つ手ははっきりしています。それはリスト形式のタグで、 <ol>
(ordered list)や <ul> (unordered list)、<li> (list item)がその対象にな
ります。しかしあるところまで来てしまうと、実際すべての機能を許可してい
ることになります (その場合、提供者を信頼するか、ここで説明した内容より
も厳しくチェックする必要があります)。それより重要なのは、追加した新しい
機能はどれもが、エラー(もしくは攻撃しやすいところ)になるとっかかりとな
る点です。

例として、同じような URI パタンで <img>(画像)タグを許可する場合を挙げま
す。許可することで、明らかに安全性が下がります。理由は、「Web バグ」の
挿入を第三者に許可してしまうからです。Web バグで、誰が、いつこのドキュ
メントを読んだのかを特定できます。 Web バグを詳しく知りたければ Section
7.7 を見てください。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.10.6. 関連事項

Web アプリケーションは文字集合(普通は ISO-8859-1)を指定しなければいけま
せん。信頼できないユーザがデータが他の文字を使っていても、許可してはい
けません。 Section 8.5 にさらに詳しい情報があります。

この種の入力をフィルタすると、間違いが起こりやすいので、他の手段も同様
に論じられてきました。選択肢の 1 つは、別の言語を使うようにユーザへ確認
を取るというもので、これは HTML よりも簡単に設計できます。デザインする
HTML がより単純になります。またその言語に対して機能に制限をかけられます
。もう 1 つの解決方法は、HTML を解析して、「安全な」内部形式に変換し、
その安全な形式を HTML に解釈し直す方法があります。

フィルタリングは入力時、出力時、もしくはその両方で実施できます。 CERT
が推奨している方法は、データを出力の過程、つまり動的なページの一部とし
てまさにレンダリングされる前でのフィルタです。正しく実施できれば、この
やり方で確実に動的なコンテンツをすべてフィルタできます。 CERT は、入力
側でのフィルタリングはあまり効果がでない、と考えています。理由は、動的
なコンテンツが HTTP という手段ではなく、 Web サイトを構成するデータベー
スの一部になっているからです。そしてこの場合、Web サーバは入力処理過程
においてそのデータを扱いません。フィルタリングが、動的なデータが入って
くるあらゆる場所で実行されない限り、データの中身は汚染されたままになっ
ているでしょう。

しかし、私はこの点に関して CERT に同意しかねます。入力と同様、出力すべ
てに対して、うっかりフィルタをかけ忘れてしまう点に問題があります。また
「汚染された」データのシステムへの侵入を許すと、どこかで厄介ごとが起こ
るのを待つ羽目になります。安全なプログラムは、入力すべてをフィルタしな
ければいけません。これらのチェックを入力フィルタの一部に入れる方が良い
場合があるからです(そうすれば、メンテナーが、そのルールは本当にそうなっ
ているのかを確認できるようになります)。そして、安全が必要となるプログラ
ムには、プログラムのあちこちで出力を行う箇所があるものの、データがプロ
グラムに入力される方法や場所はほんの数ヶ所になっている場合があります。
このようなケースでは、入力でフィルタリングする方法は優れた方法になるで
しょう。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.11. クエリ以外の実行に HTTP の GET 命令を使わせない

HTTP を利用した Web ベースのアプリケーションでは、クエリ以外の目的で
HTTP の「GET」もしくは「HEAD」命令を使わないようにしてください。 HTTP
にはさまざまな命令がたくさんあります。最も普通に使われる命令は、 GET と
POST の 2 つです。 GET も POST もフォームからデータを送信できますが、
GET 命令は URL にデータを入れて送信します。その一方、POST 命令は URL と
は別にデータを送信します。

GET をクエリ以外の命令(データの変更やお金の振り込み、あるサービスにサイ
ンアップするような)に利用すると発生してしまうセキュリティ上の問題は、攻
撃者が悪意あるフォームデータが存在する URL に対してハイパーテキストリン
クを張れるところにあります。攻撃者が犠牲者を誘導して、そのリンクをクリ
ックしたり(ハイパーテキストリンクの場合)、あるページを見たりしただけで
(HTML の画像タグから画像として情報が伝わってくる場合)、GET が実行されま
す。 GET が実行されると、犠牲者は、攻撃者が作成したフォームデータすべて
を特定のリンクへと送ります。このサイトにまたがった悪意あるコンテンツに
よる攻撃については、さらに Section 6.15 で論じます。

サイトにまたがった悪意あるコンテンツによる攻撃が、思いがけないデータを
ユーザに見せるだけであれば、それほど問題は深刻ではありません。もちろん
これはこれで問題なのですが、他にもこの機能を使った攻撃があるのが問題な
のです。たとえば、ユーザが予期せずに何かを要求しまうことで、プライバシ
ーが流出する可能性がでてきます。そうなると、違法もしくは違法になるよう
な資料を要求したように見えることで、現実に問題となったり、ユーザに何ら
かの方法で情報を要求させて、本来は公開されない情報を攻撃者へ公開させた
りするかもしれません。しかしもっと影響が深刻なのは、悪意ある攻撃者がた
だデータを見るだけでなく、サイトをまたがったリンクによって、データを改
竄する行為です。

一般的な HTTP のインタフェース(たいては CGI ライブラリ)は、GET と POST
の違いをわからなくしていますので、データ取得という点からすると双方の命
令を「同一の方法」として扱う方が便利です。しかし、データクエリ以外の何
かの処理を実際に行うなら、要求が POST 以外に何をするのかを見てチェック
する必要があります。もしそうなら、与えられたデータをフォームに入れてた
だ表示し、ユーザが本当にその要求をするつもりなのか、確認してください。
こうすることで、サイトをまたがった悪意あるコンテンツに対する攻撃を防げ
ます。ただしユーザには、簡単にワンクリックで確認できるようにしなければ
なりません。

実際、HTTP の仕様書ではこの行為を強く推奨しています。 HTTP 1.1 の仕様書
(IETF RFC 2616 セクション 9.1.1)によると、「GET や HEAD 命令を検索以外
で動かす「意味はないはず」です。これらの命令は「安全」であるはずです。
これはユーザエージェントに対して、特別な方法でその他の命令である POST
や PUT、 DELETE の代役を許可します。その結果、安全でないかもしれない処
理が要求されている、という事実をユーザが知るところとなります」。

公正を期しますが、これでは問題を完全には解決できない点に注意してくださ
い。なぜなら、ブラウザ(の設定の中)にはスクリプト化された POST で同じよ
うな動作ができるものがあるからです。たとえば、ECMAscript(Javascript)が
動作可能な Web ブラウザが下記の HTML の断片を受け取ったと仮定します。あ
るブラウザは、この HTML の断片を表示するだけで、攻撃者が定義したフォー
ムデータを強制的にユーザが自動で攻撃者が選んだ Web サイトに対して POST
命令を送ってしまいます。

  <form action=http://remote/script.cgi method=post name=b>            
    <input type=hidden name=action value="do something">               
    <input type=submit>                                                
  </form>                                                              
  <script>document.b.submit()</script>                                 

この点を指摘してくれた David deVitry 氏には感謝しています。しかしこのア
ドバイスでも問題すべては解決できません。しかしやるだけの価値はあります
。残りの問題はある程度、より賢いブラウザ(たとえば、ECMAscript がある
Web フォームを送る前には常にそのデータを確認する)や Web ブラウザの設定
(たとえば、 ECMAscript を無効にする)で解決できます。また、この攻撃はク
ロスサイト・スクリプティング攻撃の多くでは機能しません。理由は、Web サ
イトの多くは、ユーザが「script」コマンドを POST できないようにしていま
すが、URL リンクを自由に張れるようにしているからです。つまり、GET コマ
ンドの動作を制限すると、クエリに対して Web アプリケーションのセキュリテ
ィが著しく改善します。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.12. SPAM に対抗する

どこかに電子メールを送れるプログラムなら、ネットワークからの要求で SPAM
の運び屋になれます。 SPAM という言葉は通称で、正式には unsolicited bulk
email(UBE)もしくは、mass unsolicited email と言います。 unsolicited
commercial email(UCE)とも言いますが、これは誤解を生みます。SPAM すべて
が商売用ではないからです。 SPAM がなぜ深刻な問題となっているのかは、次
を参照してください。 http://mail-abuse.org/, http://spam.abuse.net/, 
CAUCE <http://http://www.cauce.org/>, and IETF RFC 2635 <http://
www.faqs.org/rfcs/rfc2635.html> SPAM を受け取ったり中継したりする人が、
SPAM によるコストの大部分を負担していて、SPAM を送った人は送るのにほと
んどコストがかかっていません。したがって、SPAM をサービス泥棒とみなして
いる人が大半で、無防備な行為だとは思っていません。

プログラムが他に送る電子メールを作成するようなら(MTA や電子メールでデー
タを送りつけるもの、メーリングリスト管理等)、プログラムが絶対に不正な電
子メールの中継をしないように作成してください。プログラムは普通、正規に
認められたユーザだけが他者に電子メールを送れるようにしてください(たとえ
ば、企業のメールサーバへ登録したり、正式にサービスに加入したり)。さらに
詳しい情報は、 IETF RFC 2505 <http://www.faqs.org/rfcs/rfc2505.html> に
あります。また、メーリングリストを運用しているなら、登録者だけが投稿可
能というルールを必ず実施してください。また「ログイン」機能を付加するこ
とで、SPAM を送りつける人が、登録・SPAM送出・脱退をするのに、多少なりと
も困難が伴います。

SPAM に対するより直接的な対抗策の 1 つに、MAPS (Mail Abuse Prevention
System LLC)や RBL (Realtime Blackhole List)に加入する方法があります。こ
こは、SPAM の出所として知られている IP アドレスの一覧を随時更新していま
す。さらに詳しい情報は http://mail-abuse.org/rbl/ を見てください。最近
の Mail Transfer Agent(MTA)の多くは、既に RBL をサポートしています。ど
のように設定するかは、それぞれの Web サイトを見てください。通常 RBL を
利用すると、ブラックホール・リストに載っている IP アドレスからのいかな
る要求も単純に拒否します。これは厳しいやり方ですが、問題を解決します。
他にも同様な機能を提供するサービスがあると思います。

システムやプログラムで電子メールを他の所に配送でき、その相手の区別が相
手ユーザの管理下にある場合、システムやプログラムの多くではデフォルトで
SPAM のブロックを有効にするようお薦めします。 MTA も対象になります。何
はともあれ検討してください。もちろんこの提案は、現実的には問題がありま
す。それは正規のユーザとのやり取りが(まれに)禁じられるかもしれない点で
す。一方、SPAM をブロックしなければ、すべての人があなたのシステムをブラ
ックリストに載せる恐れがあります(つまりあなたの電子メールは無視されま
す)。この問題は単純ではありません。あなたが何をしようとも、電子メールを
受け取らない人が出てくるからです。もちろん RBL を管理している組織をどれ
だけ信頼するか、という問題もあります。たとえば、本当は潔白なサイトがブ
ラックリストに追加されたとします。そして今回限りということで、その組織
がリストから削除されました。あなたはそれで OK でしょうか。つまり、トレ
ードオフなのです。大切なのは、SPAM を送ってくる人(潔白な人もいくらかい
ます)や SPAM をブロックしている他のシステム(SPAM を送ってくる人と同じ設
備を使っている無実な人を排除しています)と協調することではないでしょうか
。柔軟に対応しなければいけないのは自明です。議論の余地のある提案なので
、皆さんが置かれている立場を考えてみてください。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

4.13. 入力時間と負荷レベルに制限をかける

タイムアウトを設けたり、負荷レベルに制限をかけてください。ネットワーク
から入ってくるデータには特にそうです。さもないと、攻撃者は継続してサー
ビスを要求して、サービス拒否攻撃を簡単に実行できてしまうかもしれません
。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

Chapter 5. バッファオーバーフローの回避

                                    敵がこの地を囲み、お前の砦を倒し、 
                                    城郭を略奪する。                   
                                                                       
                                            旧約聖書アモス書 3 章 11 節

頻繁に発生しているセキュリティ上の弱点は、「バッファオーバーフロー」に
対する脆弱性です。バッファオーバーフローは「バッファオーバーラン」とも
言われ、さまざまなバッファオーバーフロー攻撃が存在しています(「スタック
領域破壊」や「ヒープ領域破壊」もそうです)。厳密に言えば、バッファオーバ
ーフローはプログラムの実装上の問題ですが、あまりに頻繁に発生し、かつ重
大な問題を抱えているので、あえて独立して項目を立てました。この問題がい
かに重要なのかは、CERT の勧告の内 1998 年の 13 の内の 9、1999 年の少な
くとも半分以上がバッファオーバーフロー関連であることで明らかです。
Bugtraq による 1999 年の非公式な調査でも、おおよそ 2/3 の回答がバッファ
オーバーフローがセキュリティの脆弱さの原因としています(残りの回答は「設
定ミス」が原因としています) [Cowan 1999]。これは以前からある既知の問題
ですが、未だに幾度となく現れる問題です [McGraw 2000]。【訳註：Bugtraq
は、セキュリティ関連の情報をやり取りする ML です。 ML のアーカイブ
<http://www.securityfocus.com/archive/1> が公開されています。日本語での
ML も存在しています。詳しくは、 BUGTRAQ-JP FAQ <http://
www.securityfocus.com/popups/forums/bugtraq-jp/faq.shtml#0.1.1> を見て
ください】

バッファオーバーフローは、ある値(文字列等)を固定長のバッファ領域にその
領域を越えて書き続けてしまう場合に発生します。バッファオーバーフローは
、ユーザからの入力をバッファに読み込む時にも起こりますし、プログラムの
まったく違った処理の最中にも起こる可能性があります。

安全性が求められるプログラムでバッファオーバーフローが起きると、攻撃者
がそれを悪用するケースがよくあります。バッファが C のローカル変数で実装
されていた場合、攻撃者はこのオーバーフローをその関数中で望みのコードを
強制的に実行させる手段として利用します。この攻撃のバリエーションは「ス
タック破壊(stack smashing)」攻撃と呼ぶ場合もままあります。バッファがヒ
ープ領域にあっても、状況が良くなるわけではありません。攻撃者は、オーバ
ーフローを使って、プログラム中の変数をコントロールできます。さらに詳細
な情報は、Aleph1 [1996]や Mudge [1995]、LSD [2001]を参考にするか、
Nathan P. Smith 氏のサイト http://destroy.net/machines/security/ にある
「Stack Smashing Security Vulnerabilities」を見てください。【訳註：ヒー
プ領域は、プログラムで利用するデータを格納する領域で、利用時に動的に割
り当てられ、利用が済むと解放された後、再利用に回されます。 C では
malloc(3) で確保された領域がこれに当たります】

高水準言語の大部分は、そもそもこういった問題に影響されません。理由は、
自動的に配列の大きさを変更したり(たとえば Perl)、バッファオーバーフロー
を検知して防御するようになっていたり(たとえば、Ada95)するからです。しか
し、C はこのような問題に対して、何も防ぐ手段を持ち合わせていませんし、
C++ でもこの問題を発生させるのは他愛もありません。アセンブリ言語でも何
も防御する方法がありません。言語にはそのような防御を持っているもの(たと
えば、Ada や Pascal)もありますが、通常は無効になっています(性能上の理由
です)。たとえプログラムの大部分を他の言語で書いていても、ライブラリルー
チンの多くとそのライブラリルーチンを呼び出すインタフェースコードは C や
C++ で書いてあります。したがって、他の言語が期待通りにバッファオーバー
フローを完全に防ぐとは言えません。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

5.1. C や C++ の危険なところ

C ユーザは、確保されている領域を越えることはありえないと確証できなけれ
ば、境界をチェックしない危険な関数を使うべきではありません。通常使用を
避けた方が良い(確実に防御すべき)関数には、strcpy(3)や strcat(3)、
sprintf(3)(親戚に当たる vsprintf(3))、gets(3) があります。その代わりと
して、strncpy(3)や、strncat(3)、snprintf(3)や fgets(3)の使用をお薦めし
ます。詳しくは下記で論じますので読んでください。 strlen(3)は NIL が必ず
存在するのが確実でなければ、使用を避けてください。 scanf()系 (scanf(3)
や fscanf(3)、sscanf(3)、vscanf(3)、vsscanf(3)、vfscanf(3)) は、使用す
るのに危険な場合が多々あります。最長値を把握せずにデータを文字列に渡さ
ないでください(とりわけ %s という形式は問題になります)。バッファオーバ
ーランしてしまうかもしれない他の危険な関数として(その使い方にもよります
が)、realpath(3)や getopt(3)、getpass(3)、streadd(3)、strecpy(3)、
strtrns(3)があります。 getwd(3)には注意しないといけません。getwd(3)に送
るバッファは、たった PATH_MAX バイトしかありません。

snprintf()系は残念ながらもっと問題を抱えています。 sprintf() と違って
snprintf()は、公式には ISO 1990(ANSI 1989)規格の標準 C 関数ではありませ
ん。したがって、システムすべてに snprintf() があるわけではありません。
さらに困ったことに、あるシステムの snprintf()は、バッファオーバーフロー
を実質防ぎません。ただ sprintf を呼び出すだけです。 Linux の libc4 とい
う古いバージョンは、「libbsd」ライブラリに依存していました。これが実に
嫌らしいライブラリでした。古い HP のシステムにも同様なものがありました
。 Linux の最近の snprintf は正しく動作することがわかっていて、要求され
た境界値をたしかに守っています。 snprintf() の返り値もさまざまです。
Single Unix Specification (SUS) version 2 と C99 規格では、何が返るか違
っています。結果的にわかったのは、snprintf のバージョンには文字列が NIL
で終端するのを保証しないものがある、という事実です。文字列が長すぎれば
、NIL がまったくないでしょう。 glib ライブラリ(GTK のベースになっている
もので、GNU C ライブラリの glib とは違います)には g_snprintf() がありま
す。返り値が一貫しており、常に NIL で終端します。もっと重要なのは、バッ
ファの長さを常に守っている点です。【訳註：C99 規格は、「ISO/IEC 9899:
1999 - Programming Language C」を指します。詳しくは http://
seclan.dll.jp/c99d/ を参照してください】

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

5.2. C と C++ でのライブラリによる解決策

C/C++ における解決策として、バッファオーバーフローの問題を抱えていない
関数ライブラリの利用があります。はじめのサブセクションでは、「標準 C ラ
イブラリ」を使った解決方法を説明します。効果はありますが、欠点もありま
す。次のサブセクションでは、バッファオーバーフローに対して、固定長と動
的に再確保する両方法でセキュリティ上よく発生する問題を説明します。次の
サブセクションでは、strlcpy や libmib といった、その他さまざまなライブ
ラリについて説明します。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

5.2.1. 標準 C ライブラリによる解決策

C でバッファオーバーフローを防ぐ「常套」手段(C++ でも使われています)は
、バッファオーバーフローを防いでいる標準 C ライブラリを呼び出すことです
。この解決方法は、標準関数である strncpy(3)と strncat(3)次第でどうにで
もなります。この解決策をとるには注意が必要です。使い方が意外と面倒で、
正しく扱うのが難しいからです。 strncpy(3)はコピー元の文字列がコピー先以
上の長さなら、コピー先の文字列の終端に NIL をセットしません。したがって
、strncpy(3)を呼出した後に、コピー先の終端に NIL を必ずセットするように
してください。同じバッファを何回も使い回したいなら、strncpy()を使う時に
、バッファには実際必要なものより 1 文字小さくして渡し、使う前に最後の文
字にいったん NIL をセットしてください。これは効果があります。 strncpy
(3)、strncat(3)とも、書き込みできる領域の残りの大きさを引数で渡す必要が
ありますが、この残量の計算をよく間違います(ここで間違ってしまうと、バッ
ファオーバーフロー攻撃を許してしまいます)。どちらの関数も仕組み上、バッ
ファオーバーフローが発生したかどうかを簡単に確認できません。結果として
、代替え関数である strncpy(3)は strcpy(3)に比べて、パフォーマンスが劣り
ます。これは strncpy(3)がコピー先の残り領域を NIL で埋めるためです。私
はこの最後の点について驚いた様子の電子メールをいくつか受け取りました。
しかしこの点は Kernighan 氏と Ritchie 氏共著の第二版 [Kernighan 1988、
249 頁]に確かに載っており、この動作は Linux や FreeBSD、Solaris の man
にも載っています。この strcpy から strncpy への変更は性能の著しい低下を
意味し、たいていの場合これはよろしくない結果になります。

注意！。 strncpy(s1, s2, n)は、s2 のある部分だけをコピーする場合にも使
えます。ここでは n が strlen(s2) より小さい値です。このように使われた場
合、strncpy()自身は基本的にバッファオーバーフローに対して防御する仕組み
を持っていません。つまり、n が s1 のバッファより必ず小さくなるように、
独立に処理する必要があります。また、このように使う場合、普通 strncpy()
は n 文字をコピーした後に NIL を付け加えません。このことが、strncpy()を
使ったプログラムが安全であるかどうかを判断しがたいものにしています。

sprintf()を使ってもバッファオーバーフローは防げます。しかし、そうするに
は注意が必要です。お薦めしがたい間違いを簡単に犯してしまいます。 sprinf
の制御文字にはいろいろと便利な指定方法(たとえば「%s」)があります。そし
て制御を指定する部分には、オプションフィールド長(たとえば、「%10s」)を
指定したり、精度(たとえば、「%.10s」)を指定できたりします。これらは似た
ように見えますが(違いはピリオドだけ)、まったく異なります。フィールド長
で指定する場合、最小値を指定するだけでは、バッファオーバーフローを防ぐ
のにはまったく役立ちません。これとは対照的に、精度で指定する方法では最
大値を指定し、指定した文字列は文字列変換指定に基づいて出力されます。つ
まり、これがバッファオーバーフローを防ぐのに役立ちます。文字列を扱う場
合、精度で指定する方法だけが全体の最大長を指定できることを忘れないでく
ださい。他の変換指定ではまた違う意味になります。長さに「*」を指定すると
、最大長をパラメタで渡すことができます(たとえば sizeof()の結果を)。例で
簡単に示せますので、ここでは sprintf()を使ったバッファオーバーフローを
防ぐ悪い例と良い例を挙げておきます。

 char buf[BUFFER_SIZE];                                                
 sprintf(buf, "%*s",  sizeof(buf)-1, "long-string");  /* WRONG */      
 sprintf(buf, "%.*s", sizeof(buf)-1, "long-string");  /* RIGHT */      

理屈上 sprintf()はとても便利です。それは複雑なフォーマットを指定できる
からです。ただ、sprintf()で間違いを犯すのも簡単です。フォーマットが複雑
なら、必ず変換先の大きさをすべてにおいて最大の大きさとするフォーマット
にしてください。しかし、精度を指定する部分は 1 つのパラメタの大きさしか
指定できません。生成する出力が複雑な場合は、「考えうる最大の」値を決め
るのは困難です。考えうる最大長の組み合わせに対して、プログラムが十分な
空きを確保していなければ、バッファオーバーフローの脆弱さが残されたまま
になっているでしょう。また、sprintf()は処理が完全に終わった後に、NUL を
変換先に加えます。後で加えたこの文字は忘れやすく、これが「1 バイト間違
った(off-by-one)」エラーを起こす原因になります。このように動作すると、
状況によっては痛い目にあうことになるかもしれません。

また、上記のコードで気にかけておいて欲しいのは、sizeof()という処理が配
列の大きさになる点です。「buf」が確保したメモリのポインタになるようにコ
ードを変更すると、「sizeof()」の処理すべてを修正しなければなりません(さ
もないと、sizeof はポインタの大きさを計ってしまい、これはたいていの値に
とって十分な領域とはいえません)。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

5.2.2. 静的もしくは動的に確保したバッファ

strncpy のような関数は、静的に確保したバッファを扱うのに便利です。バッ
ファは「使い物になる十分な大きさ」で確保してあり、確保した時からずっと
同じ大きさのまま、という方針でプログラムを作っています。もう 1 つの方法
は、必要な大きさのバッファを動的に確保する方法です。どちらの方法もセキ
ュリティに密接な関連があります。

固定長のバッファを使う場合に、共通したセキュリティ上の問題があります。
それは固定長のバッファはやられやすい、という事実です。これは strncpy(3)
や strncat(3)、snprintf(3)、strlcpy(3)、strlcat(3)他が抱えている問題で
す。攻撃者はいかにも長い文字列を設定する、というのが基本的な考えです。
その結果その文字列が切り捨てられると、最終的には攻撃者が望んだ状態にな
ります (開発者が意図した結果ではなく)。ひょっとすると、文字列がいくつか
の小さな部分から構成されている場合もあります。攻撃者は、最初の部分にバ
ッファを埋めつくすだけの長い文字列を入れて、後の文字列をまとめる作業を
無効にするかもしれません。ここで、具体例をいくつか挙げてみます。

 ・ gethostbyname(3)を呼び出すコードを思い浮かべてください。頭に浮かん
    だら、 hostent->h_name を固定長のバッファに strncpy か snprintf で
    コピーしてください。 strncpy か snprintf を使っているので、極端に長
    い完全修飾ドメイン名(FQDN) を入れてもオーバーフローを防げます。した
    がってこれで終わりと思われるでしょう。しかしこれでは FQDN の末尾を
    切り捨ててしまう結果になりかねません。これは非常にまずいことで、次
    に何がくるかで状況が変わってしまいます。
   
 ・ strncpy や strncat、snprintf 等を使う場合を思い浮かべてください。フ
    ァイルシステムの実体を表現したフルパスをあるバッファにコピーします
    。さらに元の値が信頼できないユーザからのもので、そのコピーが計算の
    結果をある関数に渡す処理の一部だと考えてみてください。これで安全な
    のでしょうか。ここで、攻撃者がパスの先頭に多量の「/」を埋め込むこと
    を想像してみてください。これは「/」というファイルに対する操作になっ
    てしまいます。プログラムが結果は安全だと信じて値を追加するなら、そ
    のプログラムはやられてしまうかもしれません。もしくは、攻撃者はバッ
    ファの長さに近い長いファイル名を考え出して、ファイル名を追加するこ
    とで、密かに壊してしまうかもしれません(もしくは、部分的にやられてし
    まうかもしれません)。
   
 

静的に確保したバッファを使う時には、引数となっている元になる領域と渡す
先の領域の長さをよく考えなければいけません。そして、入力や処理中に出る
中間の結果も注意深くチェックしてください。

もう一つの選択肢は、固定長のバッファを使わずに、文字列すべてを動的に確
保する方法です。この方法は GNU のプログラミング・ガイドラインで推奨して
いて、プログラムでどんな大きさの入力も扱えるようになります(メモリを越え
ない限り)。動的に文字列を確保した際に起こる問題は、確保したメモリを越え
て動作させてしまう点にあるのは、言うまでもありません。メモリは、バッフ
ァオーバーフローを起こすのではないか、と気にしている部分ではなく、プロ
グラムのどこか他の所で使い切ってしまうかもしれません。これではメモリを
どこにも確保できません。また、動的な確保はメモリを効率良く利用できない
恐れがありますので、理論的にそのプログラムが動き続けるのに十分な仮想メ
モリがあったとしても、メモリをオーバーして動作してしまう可能性は十分に
あります。さらに、プログラムはメモリをオーバーしてしまう前に、おそらく
多量の仮想メモリを使います。こうなるとたいてい「スラッシング」に陥りま
す。スラッシングが起こると、コンピュータはディスクとメモリ間での情報の
受け渡しにすべての時間を費やしてしまいます(生産的な処理をするかわりに)
。これはサービス拒否攻撃と同じ影響を与えます。入力の大きさに対して理に
かなった制限を設けると効果があります。普通プログラムで動的に文字列を確
保するなら、メモリを使い果たしてもフェイル・セーフになるように設計しな
ければなりません。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

5.2.3. strlcpy と strlcat

もう一つの方法は、OpenBSD で採用している strlcpy(3) と strlcat(3)です。
これは Miller 氏と de Raadt氏[Miller 1999]が作成しました。これは機能を
最小限に抑え、静的な大きさを持つバッファを採用しています。C の文字列を
コピーし、連結するのに異なるインタフェースを採用しています(エラーを起こ
しにくい)。これらの関数のソースとドキュメントは、 ftp://ftp.openbsd.org
/pub/OpenBSD/src/lib/libc/string/strlcpy.3 で利用でき、新しい BSD スタ
イルのオープンソースライセンスを採用しています。

まずプロトタイプを挙げます。
┌──────────────────────────────────┐
│size_t strlcpy (char *dst, const char *src, size_t size);           │
│size_t strlcat (char *dst, const char *src, size_t size);           │
└──────────────────────────────────┘
strlcpy も strlcat もパラメタでコピー先のバッファを実際の大きさで指定で
きます(コピーする文字数の最大値ではありません)。また、結果が NIL で終端
することを保証しています(大きさが 0 より大きい限りは)。忘れてならないの
は、大きさには NIL 用の 1 バイトを入れておく必要があることです。

strlcpy は、NUL で終端した元の文字列から、その size - 1 の文字をコピー
し、NIL で終端します。 strlcat は、NIL で終端してある文字列を末尾に追加
します。多く見積もっても size - strlen(dst) - 1 バイトを追加し、NIL で
終端します。

strlcpy(3) と strlcat(3)は、たいていの Unix ライクなシステムにデフォル
トではインストールされません。これが欠点と言えば欠点です。 OpenBSD では
、<string.h> の一部になっています。これはたいした問題ではありません。こ
れらは小さな関数で、自作プログラムのソースの中に入れたり(少なくともオプ
ションとして)、独立したパッケージとして読み込めます。こういったケースで
は autoconf を使って自動化するのも可能です。さらに多くのプログラムでこ
れらの関数を使えば、Linux ディストリビューションや他の Unix ライクなシ
ステムの標準構成の一部となるのもそう遠くはないでしょう。また最近になっ
て、これらの関数は「glib」ライブラリに取り込まれました(私がパッチを提供
してこのようになりました)。したがって、最近のバージョンの glib を使えば
利用できます。 glib ではこれらの関数は g_strlcpy と g_strlcat となって
いて(strlcpy や strlcat ではありません)、glib ライブラリの命名規則に沿
った形になっています。

また strlcat(3) は、長さが 0 もしくは NIL 文字が処理先の文字列(指定した
文字数の中で)にない場合に若干文法が変わっています。 OpenBSD では、長さ
が 0 ならば処理先の文字列の長さは 0 とみなします。また長さが 0 以外で
NIL 文字が処理先の文字列(文字数分)に無い場合は、処理先の長さは指定した
ものと等しいとみなします。これら規則によって、文字列への NIL の組み込み
を徹底しています。あいにく、少なくとも Solaris は(現時点では)この規則に
したがっていません。理由は、オリジナルのドキュメントにそういう記述がな
いからです。私は Todd Miller 氏と話し、OpenBSD の文法が正しいと合意しま
した (Solaris が正しくないことにも)。理由は単純です。どんな条件下であっ
ても、strlcat や strlcpy は処理先が指定した文字列の大きさを越えているか
どうかを調べた方が良いのにもかかわらず、それをしていないからです。その
ような方法をとると、core ダンプしてしまうか(メモリ範囲外にアクセスした
ため)、ハードウェアに悪影響を与えるかもしれません(メモリマップド I/O を
通じて)。つまりこうです。
┌──────────────────────────────────┐
│  a = strlcat ("Y", "123", 0);                                      │
└──────────────────────────────────┘
正しい返り値は 3(0+3=3)ですが、Solaris は 4 になります。これは処理先の
「大きさ」の長さを越えた文字を正しく見ていないためです。差し当たり、大
きさが 0 もしくは処理先に NIL 文字が無い場合を避けるようにお薦めします
。 glib の将来のバージョンでは、この相違点が隠されて、常に OpenBSD の文
法を用いる予定です。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

5.2.4. libmib

C 用のツールセットには、自動的に文字列を動的確保してくれるものがありま
す。それは Forrest J. Cavalier III 氏の「libmib allocated string
functions」で、http://www.mibsoftware.com/libmib/astring から入手できま
す。libmib は 2 種類あり、「libmib-open」は X11 と似た独自のライセンス
にしたがっていますので、明らかにオープンソースです。このライセンスは、
修正や再配布を認めていますが、再配布には別の名前を選択しなければいけま
せんし、「完全にテストされていない」と開発者は記載しています。
libmib-mature を引き続き手に入れるなら、申し込みに費用がかかります。ド
キュメントはオープンソースではありませんが、自由に利用できます。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

5.2.5. C++ std::string クラス

C++ で開発する人たちは、言語に組み込まれている std::string クラスを利用
できます。このクラスは動的な方法を採用していて、必要に応じて記憶領域を
増やしていきます。しかし注意しないといけないのは、クラスのデータが「
char *」に置き換わると (たとえば data() もしくは c_str()を使って)、再び
バッファオーバーフローの問題が表面化する点です。したがって、メソッドを
使用する場合には注意が必要になります。 c_str()は常に NIL で終端した文字
列を返しますが、data()の場合はどうなるかわかりません(実装次第ですが、ほ
とんどは NIL で終端しません)。 data()の使用を避けるか、どうしても使わな
ければならないなら、そのフォーマットを当てにしないでください。

他の文字列ライブラリを使っている開発者も同様にたくさんいますが、そのよ
うなライブラリは、他の多数のライブラリや自作の文字列ライブラリと組み合
わせになっています。そのようなライブラリを使う場合には、とりわけ注意を
払ってください。他の文字列クラスの多くは、自動的にクラスを「char *」タ
イプに変換してしまうルーチンが入っています。その結果、知らないうちにバ
ッファオーバーフローの脆弱さにはまっている可能性があります。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

5.2.6. Libsafe

(Lucent Technologies の)Arash Baratloo 氏や Timothy Tsai氏、Navjot
Singh 氏が、Libsafe を開発しました。このライブラリは、スタック破壊攻撃
に弱いことで知られるているライブラリ関数のいくつかにラッパを被せます。
このラッパ(開発者は、「ミドルウェア」の一種と呼んでいます)は、動的にロ
ードされる単なるライブラリで、strcpy(3)のような C のライブラリ関数を修
正したバージョンが入っています。この修正済みのバージョンは、オリジナル
の機能を実装してありますが、ある意味でどんなバッファオーバーフローも現
在のスタック・フレームの中に封じ込めます。当初の性能分析では、ライブラ
リのオーバヘッドはとても小さいとしています。 Libsafe のドキュメントとソ
ースコードは http://www.bell-labs.com/org/11356/libsafe.html から取得で
きます。 Libsafe のソースコードはオープンソースの LGPL ライセンスに完全
に準拠していて、Linux ディストリビュータは利用に関心を持ちつつあります
。

Libsafe の解決手段は多少は役に立つように思えます。確かに Linux ディスト
リビュータは Libsafe の採用を検討した方が良く、その解決方法はその他の人
たちも同様に検討するに価します。たとえば、Linux ディストリビューショの
Mandrake(バージョン 7.1) は採用しています。ソフトウェア開発者にとっては
Libsafe は手の込んだ防御をするのに便利な仕組みですが、本当にバッファオ
ーバーフローを防げるわけではありません。コードを開発している時に、
Libsafe だけに頼るべきではない理由がいくつかあります。

 ・ Libsafe は、明らかにバッファオーバーフローの問題を持っている、既知
    のわずかな関数だけを防御します。これを書いている時点では、防御でき
    る関数のリストは、このドキュメントで問題を抱えているとした関数のリ
    ストよりかなり短くなっています。また、あなた自身が書いた(たとえば
    while ループ中)バッファオーバーフローを起こすコードは防御してくれま
    せん。
   
 ・ libsafe がディストリビューションに入っていたとしても、インストール
    した方法によって利用に差が出ます。ドキュメントでは LD_PRELOAD を設
    定して libsafe の防御を有効にするように推奨していますが、問題はユー
    ザがその環境変数の設定をはずせるところにあります。これでユーザが実
    行するプログラムに対する防御は無効になってしまいます。
   
 ・ Libsafe は、リターンアドレスがスタック上にあるバッファオーバーフロ
    ーに対してだけ効果があります。ヒープやプロシジャー・フレームにある
    その他の変数では、あいかわらずオーバーしてしまいます。【訳註：プロ
    シジャー・フレームとは、登録済みレジスタとローカル変数が入っている
    スタック・セグメントです。activation record ともいいます】
   
 ・ あちこちにあるコンピュータ・システムすべてで libsafe(もしくは似たも
    の)が利用できると断言できない限り、自分のプログラムは libsafe が無
    いつもりで防御しなければいけません。
   
 ・ LibSafe は登録済みのフレーム・ポインタがスタック・フレームそれぞれ
    の先頭にあることを仮定しているように見えます。これは常に真とは言え
    ません。コンパイラ(gcc のような)は最適化をかけてしまいます。特に「
    -fomit-frame-pointer」というオプションは libsafe に必要と思われる情
    報を削除してしまいます。つまり、libsafe がうまく動かないプログラム
    があるかもしれないのです。 
   
libsafe の開発者たち自身も、ソフトウェア開発者たちが libsafe だけに頼っ
ていてはいけないことを知っています。彼らによれば、

   
    バッファオーバーフロー攻撃に対する最適策は、プログラムの欠陥の修正
    であることは周知の事実です。しかし、欠陥を持ったプログラムを修正す
    るには、プログラムに欠陥があることを知る必要があります。 libsafe や
    その他のセキュリティ対策を使用する本当のメリットは、まだ脆弱さを知
    られていないプログラムが、今後の攻撃に備えるという点にあります。
   
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

5.2.7. その他のライブラリ

glib(glibc ではなく)ライブラリは広く利用できるオープンソースのライブラ
リで C プログラマに対してたくさんの便利な関数を提供しています。たとえば
、GTK+ や GNOME は両者とも glib を使っています。以前にも指摘しましたが
、glib バージョン 1.3.2 には私が提供したパッチが g_strlcpy() と
g_strlcat()に適用してあります。今後のバージョンが広く利用されれば、移植
性の高いこれらの関数の利用がもっと簡単になるはずです。現状では、glib ラ
イブラリの関数がバッファオーバーフローを防ぐか否かの分析を私は結論づけ
られません。しかし、glib 関数の多くは自動的にメモリを確保し、失敗を横取
りして、訳もわからずに動かなくなります(たとえば、かわりに別のことをしよ
うとするために)。結果的に、glib 関数の大部分は、安全が求められるプログ
ラムでは利用できない場合が多くあります。 GNOME のガイドラインでは
g_strdup_printf()のような関数の使用を推奨しています。プログラムがメモリ
例外を起こした場合、すぐにクラッシュしてもかまわないなら、使用してもか
まいません。しかしそれが受け入れ難いなら、そのようなルーチンを使用する
のは、適切ではありません。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

5.3. C や C++ でのコンパイルによる解決

まったく違った観点から解決をはかろうとするものに、領域の境界チェックを
コンパイル時に行うものがあります([Sitaker 1999] のリストを参照してくだ
さい)。私見ですが、いろいろな防御手段の 1 つとして使用するなら、そのよ
うなツールは非常に有効です。しかし、この手法だけで防御するのは賢い手段
とはいえません。理由として少なくとも 2 つは挙げられます。まず、そのよう
なツールはバッファオーバーフローに対して必要な防御の一部しか行えません
(そして「完璧な」防御を行おうとすると、通常の 12 から 30 倍遅くなりま
す)。C と C++ はそもそもバッファオーバーフローを防ぐ手段を持ち合わせて
いません。次に、オープンソースであるプログラムはどんなツールを使ってコ
ンパイルするかが決められているわけではない点です。システムについてくる
デフォルトの「普通の」コンパイラを使うと、セキュリティの弱点をさらすか
もしれません。

さらに有効なツールの 1 つに「StackGuard」があります。これは、標準的な
GNU C コンパイラの修正版です。 StackGuard は「ガード」するための値(「カ
ナリア(canary)」と呼びます)をリターンアドレスが書かれている前に挿入して
動作します。バッファオーバーフローが発生してリターンアドレスを書き換え
ると、カナリアの値が(おそらく)変更され、実際に使用される前にシステムが
検出します。これは非常に有効なのですが、リターンアドレス以外の値(これを
利用してもシステムを攻撃できます)を書き換えるバッファオーバーフローには
対処できません。 StackGuard を強化して、カナリアを他のデータに対しても
使えるようにしたものが、「PointGuard」です。 PointGuard は自動的にある
値(たとえば関数のポインタやロングジャンプ・バッファ) を保護します。しか
し他の変数を PointGuard を使って保護する場合、プログラマの介在が必要と
なります(プログラマはどのデータをカナリアで保護しなければいけないのかを
判断しなければいけません)。これは有効な半面、本来保護すべきなのに必要が
ない、とうっかり判断してしまい、いとも簡単に保護を省いてしまう場合が考
えられます。 StackGuard や PointGuard、またそれと同様なものについての詳
細は Cowan [1999] を参照してください。【訳註：鳥類のカナリアは、炭鉱で
一酸化炭素の増加や酸欠状態を「検知」するために飼われていました】

これと関連して、Linux のカーネルを修正し、スタック・セグメント上でのプ
ログラムの実行を禁止してしまう方法もあります。それを行うにはパッチが必
要です (Solar Designer 氏のパッチに含まれています。 http://
www.openwall.com/linux/ を見てください)。このドキュメントを書いている時
点では、まだカーネルに取り込まれていません。技術的な理由の 1 つに、思っ
たほどその効果がでない点があげられます。攻撃者は、対象にしているプログ
ラムに既に存在している他の「面白そうな」場所 (ライブラリやヒープ領域、
スタティックなデータ・セグメント領域等)を呼び出せてしまうからです。また
Linux はスタック領域でプログラムを実行する場合があります。例として、シ
グナルや GCC の「トランポリン」の実装をする場合です。 Solar Designer 氏
のパッチでこのようなケースにも対応できますが、これがパッチを複雑なもの
している原因です。個人的には Linux 本流に組み込まれてもよいかと思います
。というのもこれによっていくぶんかでも攻撃が難しくなりますし、既存の攻
撃のある部分は防御できるからです。しかし Linus Torvalds 氏たちが考えて
いるように、このパッチが見た目ほどさまざまな防御ができない、比較的簡単
にこの防御の裏をかくことができる、という点については私も同意見です。
Linus Torvalds 氏がこのパッチを採用しない理由については、 http://
lwn.net/980806/a/linus-noexec.html を見てください。【訳註：トランポリン
(trampoline)とは、プログラムが実行している最中にプログラム自身によって
生成される、互いに独立した小さなオブジェクト・コードを指します】

要するに、まずプログラムそのものでバッファオーバーフローを防ぐように開
発するのが大切です。そのように開発した後に、StackGuard のようなツールや
テクニックを使って、さらに安全策を講じておくべきです。ソースコードから
バッファオーバーフローを追い出せるだけ追い出したら、 StackGuard はさら
に効果を発揮します。というのも StackGuard が防御のために呼ばれるような
「致命的な弱点」を減らすことができるからです。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

5.4. その他の言語

バッファオーバーフローは、Perl や Python、Java、Ada95 のような他のプロ
グラミング言語でもかなり問題になります。つまるところ、今日使っている他
のプログラミング言語(アセンブリ言語は除く)のほとんどすべては、バッファ
オーバーフローを防御しています。 C や C++ 以外の言語を使ったとしても、
もちろんすべての問題を解決できるわけではありません。詳しくは、後程論じ
るSection 7.3 にある NIL 文字の扱いを参照してください。また言語が提供し
ている基本的な機能(たとえばランタイム・ライブラリ)が利用できる環境で、
かつその機能が安全であることを保証するという問題も残っています。そのよ
うな問題はあるにせよ、安全性が求められるプログラム開発を行う場合は、他
の言語の使用を真剣に考えて、バッファオーバーフローを防いでください。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

Chapter 6. プログラムのインタフェースと内部構成をきちんとすること

                                    侵略されて城壁の滅びた町。自分の霊 
                                    を制しえない人。                   
                                                                       
                                               旧約聖書箴言 25 章 28 節
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.1. 安全なプログラムを作るためには、ソフトウェア・エンジニアリングの原
則に従うこと

Saltzer [1974] と Saltzer and Schroeder [1975]では、設計に当たって安全
を保護するのに、下記のような原則をまとめています。これは今なお有益です
。

 ・ 特権をできるだけ持たせない。ユーザやプログラムにはできるだけ権限を
    持たせないようにしてください。そうすれば、アクシデントやエラー、攻
    撃者によるダメージが最小限に抑えられます。また、こうすることで特権
    をもったプログラム間相互の影響を可能な限り抑えられるので、意図しな
    い不要で不適切な特権を利用しなくなります。このアイディアはプログラ
    ム内にも採用できます。プログラムの最小限の部分にだけ必要となる特権
    を持たせてください。やり方の詳細は、Section 6.4 を見てください。
   
 ・ 仕組みを単純に。防御システムは小さく単純明快に設計します。彼らによ
    れば、「ソフトウェアを一行毎に調査したり、ハードウェアを調査して、
    防御機構の実装をするテクニックが必要になったりします。テクニックが
    うまくいくには、小さくかつ単純明快な設計が基本になります」これを「
    KISS」の原則(「keep it simple, stupid」(こら、短くしとけ))と表現す
    る場合があります。
   
 ・ オープンな設計。防御する仕組みは、攻撃者がその仕組みの知識を持って
    ないことに頼ってはいけません。そのかわり、公開された仕組みで、パス
    ワードや秘密鍵のように比較的少ない項目 (そして簡単に変えられる)で秘
    密を守れるようにしてください。オープンな設計は、広範囲な公開された
    精査が可能で、そうすることでユーザがそのシステムの利用が適切なのど
    うかを納得できます。率直に言って、広く配布したシステムを密かにメン
    テナンスしようとするのは、現実的ではありません。デコンパイラ(逆コン
    パイラ)やハードウェアを壊してしまうことで、あっと言う間にあらゆる「
    秘密」がばれてしまう可能性があります。 Bruce Schneier 氏は、頭の切
    れるエンジニアならば、「セキュリティに関するすべてのコードは、オー
    プンソースであった方が良いと主張する」としています。またそうすると
    、広く第三者からレビューを受けられ、そこで問題となった部分も修正さ
    れることを証明しています[Schneier 1999]。
   
 ・ 完全に仲介を行うこと. すべてのアクセスをチェックしなければいけませ
    ん。チェックする仕組みは、壊されない場所に置いてください。たとえば
    、クライアント・サーバモデルであれば、サーバ側ですべてのアクセスを
    チェックする必要があります。それはユーザがクライアント側を新しく作
    成したり、既存のものを修正したりできるからです。これは、Chapter 4
    や Section 6.2 にも該当します。
   
 ・ フェイル・セーフをデフォルトとする(たとえば、パーミッションを活用す
    る方法)。デフォルトではサービスを拒否してください。防御機構はどのア
    クセスを許可しているのか、状況を認識していなければいけません。詳し
    くは、Section 6.7 と Section 6.9 を見てください。
   
 ・ 権限を集中させない。対象へのアクセスに当たって、複数の条件をつける
    のが理想的です。そうすれば、もしある防御システムが破られても、無制
    限なアクセスを許すようにはならないからです。
   
 ・ 共通した仕組みはできるだけ用いない. 共通する仕組みの数とその利用度
    合を最小限にしてください(たとえば、/tmp や /var/tmp の利用)。仕組み
    を共通化すると、そこが情報の流れの中で危険な経路になってしまったり
    、予期しない相互作用が発生したりする恐れがあります。詳しくは、 
    Section 6.10 を見てください。
   
 ・ 気持ちで受け入れられるか、簡単に使えるか。ヒューマン・インタフェー
    スは、ユーザが日常何気なく正しい防御の仕組みを使えるように、使いや
    すく設計しなければいけません。セキュリティの仕組みがユーザが思い描
    く防御の目標とマッチしたなら、過ちは減るでしょう。
   
 

セキュリティについての設計上の原則をいろいろと網羅している資料が Peter
Neumann's CHATS Principles <http://www.csl.sri.com/neumann/chats2.html>
にあります。 

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.2. インタフェースを安全に

インタフェースは、できる限り小さく(限りなくシンプルに)かつ厳密に(必要な
機能だけ)、そして例外なくそのインタフェースを使うようにする必要がありま
す。信用できる入力はほとんどないと思ってください。ユーザが見られるデー
タに制限をかけることを検討してください。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.3. データと制御を切り離す

サポートするどんなファイルに対しても、(外から来る)データとそれを実行す
るプログラムを完全に分けて設計してください。アプリケーションやデータを
見るビューアーは、外部で作成したファイルを表示する場合によく使われるの
で、それらがファイルをプログラム(「スクリプト」とか「マクロ」と言われて
います)として受け付けないようにしてください。最も危険なのは、自動実行マ
クロです。これは、アプリケーションがロードしたり、データを最初に表示し
たりした時に動作してしまいます。セキュリティの観点からすると、これは災
難が起こるのを待っているようなものです。

離れたところからダウンロードする機能をプログラムできちんとサポートしな
ければいけないなら(たとえば、既存のシステムに実装するため)、マクロの動
作に必ずきつい制限をかけなければいけません(これを「サンドボックス」と呼
んでいます)。経験上、サンドボックスを本当に正しく実装するのは困難です。
実際、単独で広範に利用されたサンドボックスの中で、再三に渡って破られな
かったものは記憶にありません(もちろん、Java も含めて)。可能なら、少なく
ともプログラムを独立したファイルに収めてください。そうすれば、他のサン
ドボックスに欠点が見つかりそれが修正されなくても、簡単にブロックできる
からです。また独立にしておくことで、コードの再利用が容易になり、役立つ
時に身近で利用できます。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.4. 特権を最小限に

以前にも書いたように、一般的な原則は、プログラムには処理に必要となる特
権を最低限にしか与えないことです(特権をできるだけ持たせない)。そうすれ
ばそのプログラムが壊れても、ダメージは広がりません。最も極端な例は、単
に安全が必要となるプログラムをまったく書かないことです。そうできれば、
そうすべきです。たとえば、可能ならプログラムに setuid や setgid をかけ
ないでください。ただの一般プログラムにして、管理者には動かす前にログを
とるように依頼してください。

Linux や Unix において、まずプロセスの特権を決定するのは、そのプロセス
id の組み合わせです。プロセスそれぞれには、ユーザやグループ両者の実、実
効、保存 id があります。 (古い Unix には「保存」id がないものもありま
す)。 Linux には特別な拡張機能として、ファイルシステムとは独立した uid
と gid が、プロセスそれぞれに用意してあります。これらの値を操作するのは
、特権を最小限に抑える上で欠くことができませんし、それらを最小限に抑え
る方法もいくつかあります(下記で論じます)。 chroot(2)も利用でき、プログ
ラムから見えるファイルを最小限にできます。 Linux や Unix には、他にも特
権を決める値がいくつかあります。たとえば、 POSIX ケイパビリティ(Linux
2.2 以上でサポートされ、他の Unix ライクなシステムでもサポートしている
ものがあります)がそれに当たります。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.4.1. 許可される特権を最小限に

もちろん最も効果的なやり方は、許可される最高の特権を素直に最小限にする
方法です。特に、できるだけ root の特権を許可するのは避けてください。ほ
んのわずかなファイル群にアクセスする必要があるだけで、プログラムに 
setuid root をかけないでください。機能毎に独立したユーザやグループアカ
ウントの作成を検討してください。

よく行う方法は、特別なグループを作成し、ファイルのグループのオーナーを
そのグループに変更する方法があります。そしてプログラムをそのグループに 
setgid します。できるなら setuid するよりも setgid した方が賢明です。そ
うしておいて、グループのメンバーにはほとんど権限を認めないようにします
(特にファイルのパーミッションを変更する権限を認めない)。

これは、ゲームソフトのハイスコアを記録する場合によく使われている方法で
す。ゲームは普通 games に setgid して、スコアファイルは games グループ
が所有しています。そしてプログラム自体や設定ファイルは、別のユーザ(root
等)が所有しているのが普通です。こうしておけば、ゲームを通じて侵入者が入
ってきても、ハイスコアをいじることはできたとしても、ゲームの実行形式や
設定ファイルには手を付けられません。後者は重大です。攻撃者がゲームの実
行形式や設定ファイル(どの実行形式を動かすかを制御している)を変更できた
なら、ゲームを動かしているユーザをコントロールできるかもしれないからで
す。

新しいグループを作るだけでは不十分な場合は、新しい仮のユーザ(実際に特別
な役割を持つ)を作成し、関連するリソースを管理してください。これの典型的
な例は Web サーバです。Web サーバは特別なユーザ(「nobody」)で設定してあ
るので、他のユーザから独立していられます。実際、Web サーバからは教えら
れることが多くあります。Web サーバは普通は起動時に root の特権を必要と
しますが(80 番ポートを利用するからです)、起動してしまうとすべての特権を
外して、「nobody」というユーザで動きます。繰り返しますが、通常仮のユー
ザは最初に動かすプログラムを所有していないので、アカウントに潜り込んで
も、プログラム自体を変更できません。結果的には、動作している Web サーバ
に侵入しても、それだけでシステムすべてのセキュリティは侵せません。

データベースシステムを利用しているなら(つまり、そのクエリ・インタフェー
スを呼び出している)、そのアプリケーションを利用しているデータベース・ユ
ーザの権限に、制限をかけてください。たとえば、ユーザが定義したほんのい
くつかのクエリを使ったアクセスだけが必要なユーザに対して、システムのス
トアド・プロシジャすべてにアクセスを許すようなことはしないでください。
実行できるのは、ストアド・プロシジャだけです。そうしておけば、たとえ誰
かが任意の文字列をクエリに無理やり入れ込んだとしても、ダメージは限られ
た範囲で収まります。直接標準的な SQL クエリをクライアントのデータとして
提供しなければならないなら、その動作を制限するようにラッパをかけてくだ
さい(たとえば、sp_sqlexec のような)。 (データベースについてのアドバイス
をしてくれた、SPI Labs に感謝します)。 

プログラムに root が確保している特権を持たせなければならないなら、POSIX
ケイパビリティの利用を早急に検討してください。そして、プログラムが利用
できる特権を最小限に押えるようにしてください。 POSIX ケイパビリティは、
Linux 2.2 や他の Unix ライクなシステムの多くで利用できます。起動後すぐ
に cap_set_proc(3)や Linux 固有の capsetp(3)ルーチンを呼び出せば、その
後はずっとそのプログラムの機能を下げたままにして、本当にプログラムが必
要としている機能に押えられます。たとえば、ネットワーク時刻デーモン
(ntpd)は、以前から root で実行してきました。それは、現在の時刻をあわせ
るためです。しかし、ntpd が CAP_SYS_TIME という 1 つのケイパビリティだ
けで動くパッチが開発されました。パッチを当てれば、攻撃者が ntpd を乗っ
取っても、そのプログラムにつけ込むのが以前よりやや難しくなりました。

「ある程度制限をかけて」と言っているのには、理由があります。それは他に
手段を用いずに POSIX ケイパビリティを使って特権を維持すると、プロセスが
root ユーザの id を使い続けるからです。重要なファイル(設定ファイルやバ
イナリ等)は root が所有しているケースが多いので、攻撃者はケイパビリティ
で制限がかかっていても、依然としてプログラムをコントロールできます。つ
まり、システムの鍵となるファイルを修正でき、root レベルの特権をすべて取
得できてしまいます。 Linux カーネルの拡張(2.4.X と 2.2.19+ のバージョン
で利用できます)は、利用可能な特権に制限をかけるのに、もっと優れた方法を
提供しています。プログラムを rootで起動し(POSIX ケイパビリティを使って)
、本当に必要なケイパビリティにまで絞りこんで、prctl(PR_SET_KEEPCAPS,1)
を呼び出します。そして、setuid() を使って root 以外のプロセスに変更しま
す。 PR_SET_KEEPCAPS はプロセスにマークをつけ、プロセスが setuid を 0
以外の値にした時に、ケイパビリティはクリアされません(通常はクリアされま
す)。このプロセスの設定は、exec() するとクリアされます。しかし、
PR_SET_KEEPCAPS は Linux 特有の拡張機能で、最近のバージョンの Linux カ
ーネルで採用されている点に注意してください。

Linux 特有のツールの 1 つに SuSE が開発した「コンパートメント」がありま
す。これを使えば、許可する特権を簡単に最小限にできます。このツールは、
ファイルシステムのルートや uid、gid、もしくはケイパビリティを設定してか
らプログラムを動かします。他のプログラムを修正することなしに、実に手軽
に実行できます。下記がバージョン 0.5 の書き方です。
┌──────────────────────────────────┐
│Syntax: compartment [options] /full/path/to/program                 │
│                                                                    │
│Options:                                                            │
│  --chroot path   chroot to path                                    │
│  --user user     change UID to this user                           │
│  --group group   change GID to this group                          │
│  --init program  execute this program before doing anything        │
│  --cap capset    set capset name. You can specify several          │
│  --verbose       be verbose                                        │
│  --quiet         do no logging (to syslog)                         │
└──────────────────────────────────┘
 

つまり下記のようにすれば、より安全な anonymous ftp サーバが運用できます
。
┌───────────────────────────────────┐
│  compartment --chroot /home/ftp --cap CAP_NET_BIND_SERVICE anon-ftpd │
└───────────────────────────────────┘
 

このドキュメントを書いている時点では、まだ未完成で、代表的な Linux ディ
ストリビューションでは利用できません。しかし状況はすぐに変わるでしょう
。このプログラムは、 http://www.suse.de/~marc からからダウンロードでき
ます。

すべての Unix ライクなシステムが POSIX ケイパビリティを実装しているわけ
ではない点と PR_SET_KEEPCAPS は現状では Linux 独自の拡張である点に注意
してください。つまり、この解決方法は移植性がありません。しかし、利用で
きる環境下でオプションの安全策の単なる 1 つとして利用するなら、この方法
を採用することによって、実際には移植性は損なわれません。また、Linux カ
ーネルが 2.2 より新しいバージョンなら、低レベルのシステムコールは用意し
てあります。しかし、利用しやすい C レベルのライブラリをインストールして
いないディストリビューションもありますので、アプリケーションで使うには
ちょっと面倒です。 Linux の POSIX ケイパビリティについてさらに詳しい情
報は、 http://linux.kernel.org/pub/linux/libs/security/linux-privs を見
てください。

FreeBSD には jail()という関数があり、これで特権を制限しています。詳しい
情報は、 jail documentation <http://docs.freebsd.org/44doc/papers/jail/
jail.html> を見てください。特権を制限するのに、特別なツールや機能拡張が
たくさんあります。 Section 3.10を見てください。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.4.2. 特権を使っている時間を最小限に

早急に特権を永久に捨て去ってください。 Linux を含む Unix ライクなシステ
ムの中には、「保存」id を実装して、「以前の」値を記録しているものがあり
ます。最も単純な解決方法は、補助グループがどれも適切なら、そのグループ
を再設定することです(たとえば、setgroups(2)を使って)。 setuid や setgid
したプログラムは、特別な理由がない限り、普通は実効 gid と uid に実 id
を設定してください。特に fork(2)した後には必ず。 root から他の特権に落
とす場合は、まず gid を変更しなければいけないことを忘れないでください。
そうしないと動かなくなります。一度 root の特権を落としてしまうと、それ
以上変更のしようがなくなります。あるシステムでは、プロセスが特権を持っ
た補助グループに属していると、グループの変更だけでは十分ではないケース
があるのも忘れないでください。

既知のバグで気をつけなければいけないものに、POSIX ケイパビリティを利用
して、権限の最小化を妨げるものがあります。このバグは、Linux カーネルの
2.2.0 から 2.2.15 に影響があり、POSIX ケイパビリティを持っている他の
Unix ライクなシステムの多くにもおそらく影響があると思います。 http://
www.securityfocus.com にある Bugtraq の id 1322 にさらに詳しい情報があ
ります。要約を挙げておきます。

   
    POSIX 「ケイパビリティ」は最近になって Linux カーネルに実装されまし
    た。これらの「ケイパビリティ」は特権を制御する方法として加わったも
    のの 1 つで、特権を持つプロセスの実行に対して、きめ細かな制御をかけ
    ることができます。ケイパビリティは 3 つ(かなり大きな)ビットフィール
    ドとして実装してあり、ビットフィールドのそれぞれのビットが、特権を
    持つプロセスが実行できる機能を表わしています。特定のビットを設定す
    ることで、特権を持ったプロセスの動作を制御できます。必要となるプロ
    グラムの特定の一部に限定して、さまざまな機能を利用するアクセスを許
    可できます。これはセキュリティの指標となります。問題は、ケイパビリ
    ティは fork()を実行するとコピーされる点にあります。つまり親プロセス
    がケイパビリティをいじると、子が継承してしまいます。これに付け入る
    には、3 つのビットフィールドそれぞれで、ケイパビリティすべてにゼロ
    (すべてのビットをオフにすることを意味します)を設定する方法がありま
    す。そうしておいてから、コードを実行する前に特権を落とそうとする
    setuid したプログラムを root で実行します。これは危険です。sendmail
    がしていることがまさにこれです。sendmail は setuid(getuid())を使っ
    て特権を落とそうとしますが、そうするのに必要なケイパビリティのビッ
    トフィールドの設定とその返り値のチェックをしなければ、その試みは失
    敗に終わります。そのままスーパーユーザの特権を持ったまま実行し続け
    、あるユーザの .forward ファイルを root として動かすことが可能にな
    り、非常に危ない状況に陥ります。
   
sendmail が使っている解決方法の一つに setuid(getuid())した後には setuid
(0) を試みる、というものもあります。通常これは失敗するはずです。成功し
たとしても、プログラムは停止してしまうでしょう。さらに詳しい情報は、
http://sendmail.net/?feed=000607linuxbug を見てください。他のプログラム
であれば、短期的には良いアイディアだと思いますが、長期的にみれば、信頼
あるシステムへのアップグレードが好ましいのに違いありません。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.4.3. 特権が有効な時間を最小限にする

setuid(2)や seteuid(2)、setgroups(2)やそれと関連した機能を使用する場合
は、プログラムがその特権を必要とする時だけに有効としているかを確認して
ください。そして利用していない時には、一時的に特権を無効にしてください
。上記でも書いたように、ユーザの入力を解析している間に、これらの特権が
無効になっているかを確かめてもかまいません。もっと平たく言えば、本当に
必要な時にだけ特権を有効にしてください。

バッファオーバーフロー攻撃には、攻撃が成功するとプログラムに任意のコー
ドを実行させてしまうものがあります。そしてそのコードは、一時的に落とし
ていた特権を再び有効にできてしまいます。つまり一時的に特権を無効にした
としても、対応できない攻撃がたくさんあるということです。常に安全なのは
、速やかに特権を完全に落としてしまう方法です。対処できない攻撃が多いと
いう理由で、「seteuid()は有害と見なす」とまで言う人もいます。そうであっ
ても、一時的にパーミッションを無効化することで、すべての種類の攻撃を阻
みます。このテクニックは攻撃を防ぐケースが多いので、プログラムの該当す
る部分でずっと特権を落とせないならば、やってみる価値はあります。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.4.4. 特権を認めるモジュールを最小限にする

わずかなモジュールにだけ特権を認めているなら、そのモジュールが安全かど
うかを判断するのはそれほど難しくありません。 1 つの方法として、特権を使
うモジュールをただ 1 つにしてしまう方法があります。そうして特権を落とし
ておけば、他のモジュールが後から呼び出されても特権を間違って使うような
ことはありません。もう 1 つの解決方法は、独立した実行形式で独立したコマ
ンドにしてしまう方法です。もう一つの解決方法は、独立した実行形式のコマ
ンドにしてしまう方法です。コマンド 1 つが複雑なツールになっていて、特権
ユーザ(たとえば root)がそれを使っておびただしい作業をしているかもしれま
せんし、一方他のツールは setuid してあるものの、小さく単純なツールで、
ほんのわずかな一部のコマンドだけを許しているかもしれません。小さく単純
なツールは、入力をさまざまな受け入れ基準に合致しているかチェックし、そ
の入力を受け入れるのかどうかを判断します。その後、入力を正しいと判断す
ると、複雑なツールにデータを渡します。小さく単純なツールは、徹底的に入
力をチェックし、複雑なツールに渡すデータを制限しなければいけません。さ
もないとそれが脆弱さになってしまいます。これらの解決方法は、いくつかの
方法を積み重ねて実行できます。たとえば、複雑なユーザのツールが、たった
1 つの setuid した「ラッパー」プログラム(入力が安全な値かどうかをチェッ
クする)を呼び出し、そのラッパーが他の複雑な信頼できるツールに情報を渡せ
ます。この方法は、GUI ベースのシステムにとって特に有効です。GUI の一部
を一般ユーザで動かし、セキュリティ関連の要求があった場合に特権を持った
プログラムへ実際の実行をまかせます。

アプリケーションには、問題をより小さく分割して、相互に信頼関係を持たな
いプログラムとして開発するのが一番良い場合があります。単純な方法として
、問題を独立したプログラムに分散し、ファイルシステムの機能を使ったり、
プログラム間で問題が起こらないよう、外に見えないようにしたりして、 (安
全に)1 つのことしか行わないようにする方法があります。もっと複雑な相互関
係が必要とされているなら、複数のプロセスに fork()するという手もあります
。分かれたプロセスがそれぞれに特権を持ちます。情報の通信経路はいろいろ
と設定可能です。まず「マスター」となるプロセスが通信経路(名前なしパイプ
や名前なしソケット)を作ってしまう方法があります。作った後に別々のプロセ
スへ fork したなら、それぞれのプロセスでできるだけ特権を落とします。こ
うすると、デッドロックに注意する必要があります。単純なプロトコルを使っ
て、信頼性が低いプロセスが信頼性が高いプロセスに対して要求を行えるよう
にします。そして、より信頼性の高いプロセスだけが、限定した要求をサポー
トするようにします。ユーザやグループのパーミッションを設定して、他の誰
かがサブプログラムを起動さえできないようにして、入り込むのを困難にしま
す。

オペレーティングシステムには、信頼性を複数の層にするコンセプトを持って
いるものがあります。たとえば、Multics のリング構造がこれに当たります。
標準的な Unix や Linux には単独のプロセス中で機能毎に複数のレベルで信頼
性を持つ手段を持ち合わせていません。下記のような感じになっています。カ
ーネルに呼び出しをかけるには特権を上げますが、そのプロセスはたった 1 つ
の信頼性のレベルしか持っていません。これが Java 2 や C#(Java のやり方の
まね)、Fluke(セキュリティ強化版 Linux の基盤)の長所になっています。たと
えば、Java 2 はある特定のファイルだけをオープンするパーミッションという
ような、きめの細かいパーミッションを指定できます。しかし、汎用的なオペ
レーティングシステムでは、現状一般的にそういった機能を備えていません。
これは近い将来にかわるかもしれません。 Java についての詳しい話は 
Section 9.6 を見てください。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.4.5. fsuid を使って、特権を制限することを検討する

Linux のプロセスはそれぞれ固有の状態値を 2 つ持っています。ファイルシス
テムのユーザ id(fsuid)とフィルシステムのグループ id(fsgid)がそれです。
これらの値はファイルシステムのパーミッションに対してチェックをかける場
合に使用します。不特定ユーザ用ファイルサーバ(たとえば NFS サーバ)を操作
するようなプログラムを作成するなら、この Linux の拡張機能の利用を検討し
てみてください。これらを使うと root の特権を維持しながら、一般ユーザの
代理でファイルアクセスする前に fsuid と fsgid を変更します。この拡張は
かなり便利で、ファイルシステムのアクセス権を(おそらく必要な)他の権限を
削除ぜずに制限をかける仕組みを提供します。 fsuid(euid は設定せずに)を設
定するだけで、ローカルユーザはそのプロセスにシグナルを送れなくなります
。また、この状況下では競合状態を避けやすくなります。しかし欠点として、
これらの呼び出しが他の Unix ライクなシステムに対して移植性がないという
点が挙げられます。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.4.6. 利用できるファイルを最小限にするため chroot の利用を検討する

chroot(2) を使えばプログラムから見えるファイルを制限できます。この機能
を活かすには、ディレクトリ(「chroot jail(chroot の牢獄)」と呼ばれていま
す)の設定を注意深く行い、設定した通りにそのディレクトリに入り込むように
する必要があります。これはプログラムのセキュリティを向上するのに、かな
り効果的な方法と言えます。見えないファイルに干渉するのは困難だからです
。しかし、すべてをこの前提に頼ってはいけません。注意しなければいけない
のは、プログラムには root の特権を持たしてはいけないこと、root の特権を
どんな方法を使っても取得できないこと、そして chroot jail を確実に設定す
ることです。使って意味がある場所にchroot(2)することを推奨します。しかし
、これだけに頼ってはいけません。そのかわりに、複数の層からなる防御手段
の一部として位置づけてください。 chroot(2)の利用方法について、いくつか
覚え書きを書いておきます。

 ・ プログラムはマシン全体に渡って共有するオブジェクトとして、ファイル
    システムではないもの(System V の IPC やネットワーク越しのソケット)
    を依然として利用しています。一番良いのは、独立した仮のユーザやグル
    ープという機能を合わせて利用する方法です。Unix ライクなシステムすべ
    ては、ユーザを分離する機能を持っているからです。こうすれば、少なく
    ともあるプログラムがやられてしまっても、他のプログラムに対してダメ
    ージが少なくなります。覚えておいてもらいたいのは、最近の Unix ライ
    クなシステムの大部分(Linux を含む)では、ある意図があって協調して動
    作しているプログラムは分離できません。悪意あるプログラムが一緒に動
    作するのが心配なら、何らかの強制的なアクセス制御もしくはチャネル切
    り替えの制限を実装しているシステムを手に入れてください。
   
 ・ 外部のファイルに対するファイルシステムのディスクリプタを、後になっ
    て利用したくないなら、必ずクローズしてください。特に、chroot jail
    の外にあるディレクトリのディスクリプタは何も持たないようにするか、
    そのようなディスクリプタが存在できないような状態にしてください (た
    とえば、Unix ソケットもしくは古い形式の /proc を経由して)。 chroot
    jail の外にあるディレクトリに対するディスクリプタがプログラムに渡っ
    てくるなら、プログラムを chroot jail の外に待避するのがよいでしょう
    。
   
 ・ chroot jail は安全のために設定しなければいけません。一般ユーザのホ
    ームディレクトリ(もしくはそのサブディレクトリに)を chroot jail と同
    じように利用してはいけません。別の場所を使用するか、「ホーム」ディ
    レクトリをこの目的のために特別に分けておいてください。ここには必要
    最低限のファイルを置いてください。普通は /bin や /etc/、/lib とおそ
    らく他に 1、2 ディレクトリぐらいでしょう (たとえば、ftp サーバなら
    /pub)。 /bin には chroot() した後に動かす必要があるものだけを置いて
    ください(そこにシェルを置くのはできるだけ避けてください。そうしても
    役に立たない時もありますが)。 /etc/passwd や /etc/group が必要にな
    るかもしれません。そうしておけば、ファイルを一覧すると正しい名前が
    表示されます。しかしそうするなら、システム上の本当の値を入れないよ
    うにし、パスワードすべてを必ず「*」に置き換えてください。
   
    /lib には必要なものだけ置いてください。ldd(1) を使って /bin にある
    プログラムが何を必要としているのかを見つけ出してください。そして必
    要なものだけを入れてください。 Linux では、ld-linux.so.2 のような基
    本的ライブラリいくつかと、あといくつかのライブラリがおそらく必要に
    なるでしょう。その一方、欠くことのできないプログラムは静的にリンク
    して再コンパイルしてください。そうすれば、動的にロードするライブラ
    リがまったく必要なくなります。
   
    普通はすべてのファイルをすっかりコピーする方が、ハードリンクをはる
    よりも賢明な方法です。ディスク領域を食ってしまいますが、chroot jail
    ファイルに対する攻撃が、自動的に正規のシステムファイルに伝搬しませ
    ん。 /proc ファイルシステムをサポートしているシステムで /proc をマ
    ウントするのは賢明ではありません。実際とても古いバージョンの Linux
    (バージョン 2.0.x で少なくとも 2.0.38)では、これは既知のセキュリテ
    ィ上の欠陥になっており、/proc にある擬似ディレクトリを利用して
    chrootしているプログラムが chroot を抜け出せます。 Linux カーネル
    2.2 ではこの既知の問題は解決していますが、他にも何かあるかもしれま
    せんので、できるだけそうしないでください。
   
 ・ プログラムが root の特権を獲得できてしまうと、chroot は効果がなくな
    ってしまいます。たとえば、プログラムが mknod(2)のような関数を呼び出
    すと、物理メモリが見られるデバイス・ファイルを作成できてしまいます
    。こうなってしまうと、カーネルメモリをいじってプログラムに望みの特
    権を与えられます。 root の特権を持ったプログラムが、chroot を抜け出
    してしまう他の例を http://www.suid.edu/source/breakchroot.c で例示
    しています。ここの例を挙げてみます。プログラムがあるファイルディス
    クリプタをカレントディレクトリ用にオープンします。サブディレクトリ
    を作り、そこに chroot します。カレントディレクトリに先程オープンし
    たカレントディレクトリを設定します。再びカレントディレクトリから上
    位ディレクトリに cd します(こうすると、現状の chroot の外に出て、実
    際のファイルシステムの root に移動してしまいます)。そして移動した先
    で chroot します。ここを読むまでに、これらの脆弱性は塞がれているか
    もしれません。しかし root の特権は、もともと「特権すべて」を意味し
    ているのは事実で、それを奪い去るのも困難が伴います。プログラムが
    root の特権を継続して必要な場合、chroot()を使用すると少しは役に立つ
    、という程度に考えていた方が良いでしょう。もちろん、プログラムを複
    数の部分に分けて、少なくともその一部を chroot jail に入れられます。
   
 

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.4.7. アクセスできるデータを最小限にすることを検討する

ユーザがアクセスできるデータ量を最小限にすることを検討してください。た
とえば、CGI スクリプトなら、ユーザが直接データを見なければならない理由
がない限り、CGI スクリプトが利用するデータはすべてドキュメントツリーの
外に置いてください。リンクを公開していなければ、誰もデータにアクセスで
きない、と誤解している人もいます。しかしこれは絶対に間違っています。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.4.8. 利用できるリソースを最小限にすることを検討する

プロセスが利用できるコンピュータのリソースを最低限にするように配慮して
ください。そうすれば、あるプロセスが「めちゃくちゃ」になってもダメージ
の範囲が狭くなります。これは、サービス拒否攻撃を防ぐのに必須の方法です
。ネットワーク系のサーバでは、それぞれのセッションに対して独立したプロ
セスを設定するのが一般的なやり方です。それぞれのプロセスはセッションが
使える CPU 利用時間等の総量に制限をかけます。こうすれば、攻撃者がメモリ
を食い潰すような要求をだしたり、CPU を 100% 使い切ったりしようとしても
、制限が働いて単独のセッションが他のタスクに支障を来すのを防ぎます。も
ちろん、攻撃者はたくさんのセッションを張れますが、これは少なくとも攻撃
にとって障害となります。どのように制限をかけるかについては Section 3.6
に詳しい情報があります(たとえば、ulimit(1))。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.5. 1 つの構成要素の機能を最小限にする

関連した手だてとして、構成要素が提供する機能の数を最小限にしてください
。構成要素がいくつかの機能を提供しているなら、より小さな機能に分解して
実装することを検討してください。そうすれば、ある機能を必要としないユー
ザは、必要としない機能だけを無効にできます。欠陥が見つかった時に、これ
は特に重要です。この方法を採用すれば、ユーザはたった 1 つの構成要素を無
効にするだけで、他は使い続けられるからです。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.6. setuid や setgid したスクリプトを使わない

Unix ライクなシステムの多く、特に Linux では、スクリプトに設定してある
setuid や setgid ビットを無視して、競合状態を避けています。これは先に述
べた通りです。 setuid したスクリプトに対する Unix ライクなシステムのサ
ポート具合はまちまちなので、新しいアプリケーションでは可能な限り避ける
のがベストです。例外として Perl は、特別な設定をほどこすことで、setuid
した Perl スクリプトが実行できるようになります。つまり本当にこの種の機
能が必要なら、 Perl を使えば setuid や setgid を使えるようになります。
この種の機能を自作のインタプリタでサポートする必要があるなら、Perl がど
うしているのかを調べてみてください。一方、簡単な方法として、setuid もし
くは setgid した小さな実行形式でスクリプトを「ラップ」し、安全な環境(環
境変数をクリアにした上で設定する)を構築してから、スクリプトを呼び出す方
法もあります(スクリプトのフルパスを使って)。攻撃者がスクリプトを絶対変
更できないようにしてください。シェルスクリプト言語にはもっと問題がある
ので、setuid や setgid をかけるべきではありません。この点の詳しい情報は
、Section 9.4 を見てください。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.7. 設定を安全にし、安全なデフォルトを使用する

現状セキュリティ上で一番問題となるのは、設定にあるとされています。した
がって次の 2 点には労力をかけてください。(1)初期インストールを安全にす
ること。(2)安全を維持しつつ、システムを簡単に再設定できること。

インストール作業中に、作業用「デフォルト」パスワードを決して設定しない
でください。新しい「ユーザ」を設定する必要があるなら、行っても結構です
。絶対にわからないパスワードを設定して、管理者がパスワードを設定する時
間を残しておいてください(パスワードを設定する以前もシステムを安全にして
おきます)。管理者はおそらく多数のパッケージをインストールするので、パス
ワードを設定したかどうかを十中八九忘れてしまいます。デフォルトのパスワ
ードで作成しても、おそらく管理者は設定したことさえ知らないかもしれませ
ん。 

管理者が設定する機会がくるまで、プログラムに対しては、アクセス制限を最
大限にかけるポリシを維持してください。設定当初に「サンプルにある」作業
用ユーザを作ったり、「すべてにアクセスを許す」設定をしたりしないでくだ
さい。現にユーザは「すべてをインストール」(利用できるサービスをすべてイ
ンストール) する場合が多く、そのままサービスの大半を設定しないままにし
ておきます。既存の認証システム次第で、もっと緩やかなポリシが適当である
とプログラムが決めてしまう場合もあります。たとえば ftp サーバでは、ユー
ザのディレクトリにログインできるユーザには、ユーザのファイルにアクセス
を許すよう正式に認めています。しかしそのような前提条件には注意を払って
ください。

インストレーション・スクリプトは、できる限り安全にプログラムをインスト
ールしてください。デフォルトでは、root もしくは他のシステム関連のユーザ
がオーナーになってすべてのファイルをインストールし、その他のユーザが書
き込めないようにしています。これで root 以外のユーザがウイルスをインス
トールするのを防ぎます。実際、信頼できるユーザ以外には、読み込みもでき
ないようにするのが最善です。 root 以外のユーザが root と同じ様にインス
トールができる場所を用意してください。そうすれば、root の特権のないユー
ザやインストーラを信頼しきっていない管理者でも、そのプログラムを利用で
きます。

インストールする時には、セキュリティに必須の前提がなんであっても、それ
が正しいかどうか必ずチェックしてください。ライブラリのルーチンには、あ
るプラットフォームで安全ではないものがあります。この点については、
Section 7.1 の議論を見てください。複数のプラットフォームでアプリケーシ
ョンが動作するのがわかっているなら、プラットフォーム特有の属性をチェッ
クする必要はありません。しかし、複数のプラットフォームのどれか 1 つにだ
けプログラムをインストールするなら、必ずチェックする必要があります。さ
もなければ、プログラムをインストールするのにマニュアルで無効にする必要
があるはずです。なぜなら、インストールした結果が安全かどうかがわからな
いからです。

設定はインストール後の設定も含めて、できるだけ簡単明瞭にできるようにし
てください。できるだけ「安全な」方法を使うようにしてください。さもない
と、ユーザの多くは、リスクを理解せずに安全でない手段を選んでしまうでし
ょう。 Linux では linuxconf のような便利なツールがあり、ユーザが既存の
構成を利用して簡単にシステムを設定できます。

設定用言語があるなら、ユーザが特別に許可しない限りデフォルトではアクセ
スを拒否してください。サンプルの設定ファイルには、解りやすいコメントを
たくさん入れてください。それがあれば、管理者は設定が何であるのか理解し
ます。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.8. 初期値を安全にロードする

プログラムの多くは、初期化ファイルを読んでデフォルトの設定ができます。
攻撃者が使用する初期化ファイルの変更、作成、修正を絶対できないようにし
てください。カレントディレクトリを初期化ファイルの情報源にするべきでは
ありません。エディタやブラウザとしてプログラムを利用したなら、別の誰か
がコントロールしているディレクトリをユーザが見てしまうかもしれないから
です。そうではなく、プログラムが普通のユーザアプリケーションなら、ユー
ザのデフォルトの設定は、そのユーザのホームディレクトリに、隠しファイル
やディレクトリとして置いてください。そのプログラムが setuid や setgid
してあるなら、ユーザがコントロールしているファイルを信頼できない(悪意を
持っているかもしれない)入力として慎重にフィルタをかけない限り、そのファ
イルを読んではいけません。信頼できる設定値は、まったくどこか違ったとこ
ろから(普通は /etc 下のファイルから)ロードしてください。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.9. フェイル・セーフ

安全が必要なプログラムは、いつも「フェイル・セーフ」にしてください。つ
まり、プログラムが正しく動作しなくなっても、一番安全な結果に落ち着くよ
うに設計してください。セキュリティに敏感なプログラムは、何らかの間違っ
た動作を検知したなら (異常な入力や「起こり得ない」状態になる等)、プログ
ラムはすぐにサービスを拒否し、要求を処理するのを止めてください。「ユー
ザが意図することを探り出そう」等は、しないでください。ただサービスを拒
否してください。こうすると、時として信頼性や使い勝手が悪くなるかもしれ
ません(ユーザの立場からすると)。しかし安全性は高まります。わずかですが
こうしたくない場合もあります(たとえば、サービス拒否が守秘義務や保全性を
失うよりも悪いケース)。しかしそれは非常にまれです。

私は「いっしょくたに機能しなくなる」ではなく、「その要求の処理を止める
」ことを推奨している点に注意してください。特に、大部分のサーバは、悪意
ある入力があっても完全に停止すべきではありません。完全に停止してしまう
と、ちょっとしたことでサービス拒否攻撃が可能になるからです(攻撃者は不要
なビットを送るだけで、サービスを使えなくしてしまいます)。サーバ全体を落
とす必要がでてくる場合もあります。特に「そうはならない」状態は、問題が
発生する兆候なので、とりあえず継続し続けるのは賢い方法とは言えません。

不成功を検知した場合は、返って来るエラーメッセージを何にするかを慎重に
検討してください。何も返してこないと問題を診断するのが困難になりますし
、逆に、過剰な情報は攻撃者を結果的に助けることになるかもしれません。一
般に適切なのは、「access denied」や「miscellaneous error encountered」
を返して、より詳細な情報を監査ログ(その情報を見る人をコントロールできる
場所にある)に書く方法です。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.10. 競合状態を避ける

「競合状態」は次のように定義されています。「イベント同士が動作する相対
的なタイミングが、思いもよらない依存関係に陥ってしまった危険な動作状態
」 [FOLDOC]。競合状態は通常、1 つ以上のプロセスが共有リソース(ファイル
や変数等)にアクセスする時に伴う現象で、複数のアクセスを適切に制御できな
くなります。

通常プロセスはアトミックには動作しません。別のプロセスは基本的に 2 つの
命令間に割り込みます。安全が必要となるプログラムのプロセスが、この割り
込みに備えていなければ、別のプロセスが妨害できる可能性がありますん。安
全が必要なプログラムが動いている間に、別プロセスのコードがいくつ動いて
、それがどんな操作の組み合わせであっても、プログラムは正確に動かなけれ
ばいけません。

競合状態の問題は、2 つのカテゴリに分類できます。

 ・ 信頼できないプロセスによる妨害。セキュリティの分類ではこの問題を「
    シーケンス」もしくは「非アトミック」状態と呼んでいます。これらの状
    態は、他の異なるプログラムのプロセスが動くことで発生します。安全な
    プログラムの命令ステップ間に、他の動作が「忍び込み」ます。攻撃者が
    この問題を引き起こすことを狙って、他のプログラムを実行したのかもし
    れません。このドキュメントではこれらをシーケンス問題と呼びます。
   
 ・ 信頼されたプロセスによる妨害(安全なプログラムの観点から)。セキュリ
    ティ上の分類では、デッドロックやライブロック、ロック失敗状態と呼び
    ます。この状態は「同じような」プログラムのプロセスが動くことで発生
    します。それぞれのプロセスは「同じような」特権を持っているので、正
    しく制御していないとお互いに干渉し合って他のプログラムが実行できな
    くなってしまうかもしれません。この種の干渉が時として攻撃に利用され
    ます。このドキュメントではこれらをロック問題と呼びます。
   
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.10.1. シーケンス(非アトミック)問題

一般的に、任意のコードが 2 つの操作間で実行されると操作の組み合わせによ
って機能しなくなるものすべてを、注意深くチェックしなければいけません。

共有している変数をロードしたりセーブする場合、普通は独立した操作で実行
し、アトミックな操作にはなっていません。どういうことかと言うと、「増分
する変数」の操作は、通常ロードして、増分して、保存するという操作に置き
換えます。したがって、変数のメモリを他のプロセスと共有していれば、増分
の操作に干渉してしまうかもしれません。

安全が必要なプログラムは、要求を許可すべきなのかを判断し、許可できれば
実行します。そのプログラムが判断にもとづいて動作する前に、信頼できない
ユーザがその判断結果を使って、何かを変更する手段があってはいけません。
この種の競合状態は「チェック時が使用時(time of check - time of use
(TOCTOU))」競合状態と呼ばれる時もあります。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.10.1.1. ファイルシステムのアトミックな実行

アトミックな動作の実行が機能しなくなる問題は、ファイルシステムでも度々
発生します。ファイルシステムというものは、たくさんのプログラムが共有し
ているリソースです。プログラムには、他のプログラムがリソースを使うと干
渉を受けてしまうものがあります。安全が必要なプログラムでは、リクエスト
が許可されるかどうかの判断に際して open(2) に先立って access(2) を実行
するのは止めてください。理由は、ユーザがこの呼び出しの間にファイルを移
動して、そのかわりに自分で選んだファイルにシンボリックリンクを張ってし
まう恐れがあるからです。安全が必要なプログラムは、実効 id やファイルシ
ステム id を設定せずに、直接 open を呼び出した方が賢明です。 access(2)
の安全な使用も可能ですが、それはユーザがそのファイルやファイルシステム
のルートからのパスにそったディレクトリに影響を与えられない場合に限りま
す。

ファイルを作成する時には、O_CREAT | O_EXCL モードを使ってオープンし、パ
ーミッションをきつく制限した(現在のユーザに限定した)ものだけを許可しな
ければいけません。また、open が失敗した場合にも備える必要があります。フ
ァイルを open できる必要があるなら(たとえば、サービス拒否攻撃を防ぐた
め)、 (1)「ランダム」なファイル名、(2)上記のように開く、(3)open が成功
したら繰り返さない、ということを毎時行なわなければなりません。

普通のプログラムがファイルをきちんと作成しないと、セキュリティ上の弱点
になる可能性があります。たとえば、「joe」というテキストエディタは、「
DEADJOE」という、シンボリックリンクに関する脆弱性を抱えています。 joe
をイレギュラーに終了した場合(システムクラッシュや xterm を閉じる、ネッ
トワーク接続が切れる等)、joe が開いていたバッファを「DEADJOE」というフ
ァイルに無条件で追加します。 root が通常 joe を使うディレクトリの中で
DEADJOE のシンボリックリンクを作成するとやられてしまうかもしれません。
こうなると、joe はゴミデータをもしかすると機密事項を含んでいるファイル
に追加するようになって、結果としてサービス拒否になったり、悪意のないア
クセスが発生したりします。 

他の例として、ファイルのメタ情報をいろいろ操作する作業を行う場合(オーナ
ーの変更、ファイルの状態確認、パーミッションビットの変更等)、まずファイ
ルを開いて、開いたファイルに対して操作してください。つまりこれは、chown
()や chgrp()、chmod()のようなファイル名を受けとる関数ではなく、fchown()
や fstat()、fchmod()システムコールを使うことを意味しています。こうする
ことで、プログラムが動作している間にファイルの置き換わりを防げます (お
そらく競合状態も)。たとえば、あるファイルを閉じてから、chmod()を使って
パーミッションを変更すると、攻撃者はその 2 ステップ間にそのファイルを移
動もしくは削除し、別のファイルに対してシンボリックリンクを張ってしまえ
るかもしれません(たとえば、 /etc/passwd に対して)。他の興味深いファイル
の 1 つとして /dev/zero があります。このファイルは無限大のデータストリ
ームを入力としてプログラムに渡せます。攻撃者が途中でファイルを「切り替
え」たなら、危険な結末になるやもしれません。

しかし、さらに面倒なことがあります。ファイルを作成する時は、できるだけ
最低の権限を与えた上で、望むならもっと権限を広げるように変更しなければ
いけない点です。一般的には、umask か open 時のパラメタを使って、ユーザ
やそのユーザのグループが最初にアクセスした時に制限をかける必要がありま
す。たとえば、あるファイルを作成し、最初は誰でも読める状態から「誰でも
読める」ビットを落とそうとすると、攻撃者はパーミッションビットが OK で
ある間にファイルを開こうとします。たいていの Unix ライクなシステムでは
、パーミッションは open 時にチェックされるだけなので、意図したものより
高い特権を攻撃者が持つ結果になるかもしれません。 

一般的に Unix ライクなシステムにおいて、複数のユーザがあるディレクトリ
に書き込みができるなら、そのディレクトリに「sticky」ビットを設定した方
が良いでしょう。sticky なディレクトリを実現した方が具合が良くなります。
しかし、この問題を完全に避けるなら、信頼できる特別なプロセスだけがアク
セスできるディレクトリを作る(慎重に実装する)方が、より優れています。こ
れまでの Unix で一時的に使用するディレクトリ(/tmp や /var/tmp)は、普通
「sticky」ディレクトリとして実現されていますが、それでもセキュリティ上
のあらゆる問題が表面化しています。次からその点を見ていきましょう。 

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.10.1.2. テンポラリ・ファイル

テンポラリ・ファイルを作成する時に、アトミックな操作を正しく実行する上
での問題が顕著に現れます。これまで Unix ライクなシステムでは、テンポラ
リ・ファイルは /tmp もしくは /var/tmp ディレクトリに作ってきており、ユ
ーザすべてが共有していました。安全が必要なプログラムが動作している間、
他のファイル(たとえば、/etc/passwd) に対するシンボリックリンクをテンポ
ラリ・ディレクトリに作成する罠を攻撃者は仕掛けてきました。攻撃者の狙い
は、安全が必要なプログラムが、ある特定のファイル名が存在しないと判断す
る状況を作り上げてから、攻撃者が別のファイルへのシンボリックリンクを張
って、安全が必要なプログラムにある操作を実行させる状態です(実際は意図し
ていないファイルを開いてしまっている)。この方法でよく重要なファイルが壊
されたり、修正されたりします。普通のファイルを作成するようなこの手の攻
撃のバリエーションはたくさんあります。この攻撃は、安全なプログラムで使
用するテンポラリ・ファイルが存在するのと同じディレクトリに、攻撃者がフ
ァイルシステム・オブジェクトを作成できる (さもなければアクセスできる)と
いう仮定にもとづいています。

共有ディレクトリにファイルを作成する上で共通の問題点は、使用を予定して
いるファイル名が、作成時に既に存在していないことを保証しなければいけな
い点です。ファイルを作成する「前」にチェックするのは効き目がありません
。理由は、チェック後かつファイルの作成前に、別のプロセスがそのファイル
名でファイルを作成できてしまうからです。「予測不可能」もしくは「ユニー
ク」なファイル名を使うのも、およそ効果がありません。それは、名前の推測
が成功するまで、別プロセスが何度でも推測できるからです。

基本的に、共有している(sticky をかけてある)ディレクトリでテンポラリ・フ
ァイルを作成するには、次のことを繰り返し行う必要があります。(1)「ランダ
ム」なファイル名を作成すること、(2)O_CREAT | O_EXCL を使って open し、
パーミッションできつい制限をかけること、(3)open が成功したなら、繰り返
さないこと、です。

1997 年版の「Single Unix Specification」によると、任意にテンポラリ・フ
ァイルを作成するのに望ましい方法は、tmpfile(3)を使う、となっています。
tmpfile(3)関数はテンポラリ・ファイルを作成し、それに対応したストリーム
を open し、そのストリームのディスクリプタを返します(失敗すると NULL を
返します)。あいにく、ファイルが安全に作成される保証は仕様上一切ありませ
ん。このドキュメントの旧版で、実装すべてが安全かどうか確信できないので
心配だ、と述べました。その後、古い System V システムで tmpfile(3)の実装
が安全ではないことがわかっています(tmpnam(3) と tempnam(3)も同様に安全
でない)。もちろん tmpfile(3)を実装しているライブラリは、そのようなファ
イルを安全に作成すべきですが、ユーザはシステムのライブラリにセキュリテ
ィ上の欠陥があることを、必ずしも気付くわけではありません。場合によって
はその件について、何も打つ手がない時もあります。

Kris Kennaway 氏は、テンポラリ・ファイルの作成に当たって、一般に
mkstemp(3) の使用を推奨しています。テンポラリ・ファイルを作るなら、自分
自身で関数を作り上げて利用するよりも、よく知らたライブラリを使った方が
良い、というのが理屈です。そしてこの関数はよく知られた使い方を採用して
います。これはかなりもっともな見解です。 mkstemp(3)を使うなら、私はこれ
に加えて必ず umask(2)を使って、テンポラリ・ファイルのパーミッションが所
有者だけになるように制限をかけます。これは mkstemp(3)の実装(基本的には
古い物)には、テンポラリ・ファイルをすべてのユーザに対して、読み書き可能
にしているものがあるからです。この状態になると攻撃者は、このディレクト
リにプライベートなデータを読み書き可能になります。多少厄介なのは、
mkstemp(3)が直接には TMP や TMPDIR といった環境変数をサポートしていない
点です(下記で論じます)。そこで環境変数をサポートしたいとなると、自分で
サポートできるようにコードを追加しなければいけません。ここで、環境変数
をサポートした C で書いた mkstemp(3)の使い方を示したプログラムを掲載し
ます。これで、TMP もしくは TMPDIR のサポートを追加することで、直接両者
の操作が可能になります。

#include <stdio.h>                                                              
#include <stdlib.h>                                                             
#include <sys/types.h>                                                          
#include <sys/stat.h>                                                           
                                                                                
void failure(msg) {                                                             
 fprintf(stderr, "%s\n", msg);                                                  
 exit(1);                                                                       
}                                                                               
                                                                                
/*                                                                              
 * Given a "pattern" for a temporary filename                                   
 * (starting with the directory location and ending in XXXXXX),                 
 * create the file and return it.                                               
 * This routines unlinks the file, so normally it won't appear in               
 * a directory listing.                                                         
 * The pattern will be changed to show the final filename.                      
 */                                                                             
                                                                                
FILE *create_tempfile(char *temp_filename_pattern)                              
{                                                                               
 int temp_fd;                                                                   
 mode_t old_mode;                                                               
 FILE *temp_file;                                                               
                                                                                
 old_mode = umask(077);  /* Create file with restrictive permissions */         
 temp_fd = mkstemp(temp_filename_pattern);                                      
 (void) umask(old_mode);                                                        
 if (temp_fd == -1) {                                                           
   failure("Couldn't open temporary file");                                     
 }                                                                              
 if (!(temp_file = fdopen(temp_fd, "w+b"))) {                                   
   failure("Couldn't create temporary file's file descriptor");                 
 }                                                                              
 if (unlink(temp_filename_pattern) == -1) {                                     
   failure("Couldn't unlink temporary file");                                   
 }                                                                              
 return temp_file;                                                              
}                                                                               
                                                                                
                                                                                
/*                                                                              
 * Given a "tag" (a relative filename ending in XXXXXX),                        
 * create a temporary file using the tag.  The file will be created             
 * in the directory specified in the environment variables                      
 * TMPDIR or TMP, if defined and we aren't setuid/setgid, otherwise             
 * it will be created in /tmp.  Note that root (and su'd to root)               
 * _will_ use TMPDIR or TMP, if defined.                                        
 *                                                                              
 */                                                                             
FILE *smart_create_tempfile(char *tag)                                          
{                                                                               
 char *tmpdir = NULL;                                                           
 char *pattern;                                                                 
 FILE *result;                                                                  
                                                                                
 if ((getuid()==geteuid()) && (getgid()==getegid())) {                          
   if (! ((tmpdir=getenv("TMPDIR")))) {                                         
     tmpdir=getenv("TMP");                                                      
   }                                                                            
 }                                                                              
 if (!tmpdir) {tmpdir = "/tmp";}                                                
                                                                                
 pattern = malloc(strlen(tmpdir)+strlen(tag)+2);                                
 if (!pattern) {                                                                
   failure("Could not malloc tempfile pattern");                                
 }                                                                              
 strcpy(pattern, tmpdir);                                                       
 strcat(pattern, "/");                                                          
 strcat(pattern, tag);                                                          
 result = create_tempfile(pattern);                                             
 free(pattern);                                                                 
 return result;                                                                 
}                                                                               
                                                                                
                                                                                
                                                                                
main() {                                                                        
 int c;                                                                         
 FILE *demo_temp_file1;                                                         
 FILE *demo_temp_file2;                                                         
 char demo_temp_filename1[] = "/tmp/demoXXXXXX";                                
 char demo_temp_filename2[] = "second-demoXXXXXX";                              
                                                                                
 demo_temp_file1 = create_tempfile(demo_temp_filename1);                        
 demo_temp_file2 = smart_create_tempfile(demo_temp_filename2);                  
 fprintf(demo_temp_file2, "This is a test.\n");                                 
 printf("Printing temporary file contents:\n");                                 
 rewind(demo_temp_file2);                                                       
 while (  (c=fgetc(demo_temp_file2)) != EOF) {                                  
   putchar(c);                                                                  
 }                                                                              
 putchar('\n');                                                                 
 printf("Exiting; you'll notice that there are no temporary files on exit.\n"); 
}                                                                               

Kennaway 氏は、mkstemp(3)を使えないなら、mkdtemp(3)を使ってディレクトリ
をつくるように推奨しています。こうすれば、外部から守れます。最終的に、
安全でない mktemp(3)を使わなければならないなら、予測できない文字をたく
さん使うようにも提案しています。 10 文字がお勧めです(libc が許せば)。こ
うすれば、ファイル名は簡単には推測できなくなります(6 文字だと、5 文字は
PID で取られてしまうので、ランダムに残されたのは 1 文字だけになってしま
います。これでは攻撃者に簡単に競合状態をしかけられてしまいます)。これに
加えて tmpnam(3)の利用も避けるように提案します。スレッドが動いていて
tmpnam(3)を使用をすると、どうなるのかわかりません。また TMP_MAX を越え
て使用すると(実用上、1 つのループ内で使用しなければいけません)正しい動
作が保証できません。

概して mktemp(3) や tmpnam(3)のような、安全でない関数の使用は避けるべき
です。使用するなら、セキュリティを脅かす点に特別な処置を講じたり、安全
なライブラリの実装のテストをインストールの一環として行ってください。問
題がいろいろあってもなお、/tmp や誰でも書ける(もしくはグループを信頼し
ていないなら、グループで書ける)ディレクトリにファイルを作って、mk*temp
()を使いたくないなら(たとえば、名前が事前にわかっているファイルを意図し
て)、常に O_CREAT と O_EXCL フラグを付けて open()を呼び出し、返り値をチ
ェックしてください。 open()が失敗したなら、その時は適切に後処理してくだ
さい(たとえば、exit する)。

GNOME のプログラミング・ガイドラインでは、ファイルシステム・オブジェク
トを共有の(テンポラリの)ディレクトリに作成する場合、下記の C コードを推
奨しています。これは最小限のセキュリティでファイルを作成するのが目的で
す。

 char *filename;                                                       
 int fd;                                                               
                                                                       
 do {                                                                  
   filename = tempnam (NULL, "foo");                                   
   fd = open (filename, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, 0600);    
   free (filename);                                                    
 } while (fd == -1);                                                   

ここで注目なのは、安全でない関数の tempnam(3)が使われていても、ループ内
部で O_CREAT と O_EXCL を使って、セキュリティ上の弱点をカバーしている点
です。注目して欲しいのは、ファイル名を free()する必要があるところです。
処理が終わったら、close()や unlink()すべきです。標準 C 入出力ライブラリ
を使いたいなら、fdopen()を「w+b」で使用して、ファイルディスクリプタを
FILE * に変えてください。この解決方法は、NFS version 2 (v2)のシステムで
はうまくいかないでしょう。理由は、古い NFS が O_EXCL をきちんとサポート
していないからです。この解決方法にはちょっとした欠点もあって、tempnam
を安全に使わないと、コンパイラやセキュリティ・スキャナがうるさく警告を
出すかもしれません。これは mkstemp(3)では問題となりません。

シェルスクリプトでテンポラリ・ファイルが必要ならば、パイプを使ってロー
カルディレクトリ(たとえば、ユーザのホームディレクトリ内のどれかに)や、
場合によってはカレントディレクトリを利用するのが適切でしょう。こうすれ
ば、ユーザが許可しない限りは共有はありえません。どうしても /tmp のよう
な共有ディレクトリにテンポラリファイルを作りたい、もしくは必要なら、従
来からのシェル上のテクニックを使って、ファイル名のひな形にプロセス id
を組み込み、いつも通りに「>」でファイルを作っては、いけません。シェルス
クリプトは「$$」を使って pid を示しますが、攻撃者は簡単に pid を特定も
しくは推測できます。そうして攻撃者は、同じ名前で事前にファイルを作成し
たり、リンクしたりしてしまいます。つまり、下記の「ありがち」なシェルス
クリプトは、安全ではありません。

   echo "This is a test" > /tmp/test$$  # DON'T DO THIS.               

シェルスクリプトでテンポラリファイルが必要でかつ、/tmp に置きたい場合は
、 mktemp(1)が解決方法になるのと思います。mktemp(1)はシェルスクリプトで
の利用を前提にしています。 mktemp(1)と mktemp(3)は別物で、mktemp(1)は安
全です。正直言うと、私はシェルスクリプトで共有ディレクトリにテンポラリ
ファイルをしょっちゅう作っているわけではありません。そのようなファイル
をプライベートなディレクトリに作成するか、パイプを使うかする方が好まし
いと思います。しかしどうしても必要なら、mktemp(1)でひな形を作って、
O_EXCL でファイルやディレクトリを作成し、最終的にファイル名を返すように
します。 O_EXCL を使えば、/tmp のような共有ディレクトリでも安全になりま
す(ただし NFS version 2 を使っていなければ)。ここで、正しい例として
mktemp(1) を Bourne シェルで利用してみます。この例は mktemp(1)の man か
らそのまま持ってきました。

 # Simple use of mktemp(1), where the script should quit               
 # if it can't get a safe temporary file:                              
                                                                       
   TMPFILE=`mktemp /tmp/$0.XXXXXX` || exit 1                           
   echo "program output" >> $TMPFILE                                   
                                                                       
  # Simple example, if you want to catch the error:                    
                                                                       
   TMPFILE=`mktemp -q /tmp/$0.XXXXXX`                                  
   if [ $? -ne 0 ]; then                                               
      echo "$0: Can't create temp file, exiting..."                    
      exit 1                                                           
   fi                                                                  

テンポラリファイル名は、再利用しないでください(つまり削除して再作成しま
す)。いかに「安全な」テンポラリのファイル名を最初に得られたとしてもです
。攻撃者は、オリジナルのファイル名を見つけて、二度目に再利用する前に乗
っ取ってしまうかもしれません。もちろん適切なパーミッションを常にかけて
ください。たとえば、誰でも、もしくはあるグループがそのファイルにアクセ
スする必要があるなら、そのアクセスだけを許可してください。さもなければ
、モードを 0600 にしておいてください(すなわち、所有者だけが読み書きでき
ように)。

きちんと後始末をしてください。終了処理を使うか、UNIX ファイルシステムの
実際の処理方法を利用して、作成とともにファイルを unlink()してください。
そうするとディレクトリ・エントリは消えてしまいますが、ファイル自体はフ
ァイルを指し示す最後のファイル・ディスクリプタが閉じるまではアクセスで
きるようになっています。そうすれば、プログラム内からはファイル・ディス
クリプタ経由でファイルにアクセスし続けられます。ファイルを unlink する
のは、コードをメンテナンスするのに非常に役立ちます。ファイルはプログラ
ムがクラッシュしたとしても自動的に削除されます。すぐに unlink すると管
理者がディスクスペースがどのくらいあるかがわかりにくくなるという問題も
多少はあります。それは単純に名前ではファイルシステムを見られなくなるか
らです。

環境変数の TMP や TMPDIR の値が確実に信頼できるところから得られ、コード
が Unix ライクなシステム向けなら、それらの環境変数を尊重してもよいかも
しれません。そうすれば、ユーザはテンポラリファイルをホームディレクトリ
下のサブディレクトリのような共有していないディレクトリに移せます(そして
ここで論じた問題を回避できます)。 Bastille の最近のバージョンでは、ユー
ザ間で共有を減らすように、これらの変数を設定できるようになっています。
残念ながら、ユーザは TMP や TMPDIR に共有ディレクトリ(たとえば /tmp)を
設定しているケースが多く、依然として安全が必要なプログラムでは、これら
の環境変数が設定してあっても、正しくテンポラリファイルを作成する必要が
あります。 GNOME の解決方法には長所が 1 つあります。少なくともあるシス
テムでは、 tempnam(3)は自動的に TMPDIR を利用しますが、mkstemp(3)で同様
なことをするには、さらにコードを書かなければならないからです。テンポラ
リディレクトリ用にさらに環境変数(TEMP のような)を作らないようにしてくだ
さい。特にアプリケーション毎に別の環境変数名を作らないでください (たと
えば、「MYAPP_TEMP」のように使わないこと)。作成してしまうと、システム管
理がとても複雑になってしまいます。特定のアプリケーション用に専用のテン
ポラリファイルを望んでいるユーザが、そのアプリケーションを動かす時に環
境変数を独自に設定できてしまいます。もちろん、これらの環境変数が信頼で
きないソースで設定されてしまったなら、これらを無視しなければいけません
。Section 4.2.3 にあるアドバイスに従うなら、どのみちそうなるでしょう。

これらのテクニックは、テンポラリディレクトリが NFS version 2 (NFSv2)で
マウントした、リモートのディレクトリであるとうまく動きません。それは
NFSv2 がきちんと O_EXCL をサポートしていないからです。詳しいことは 
Section 6.10.2.1 を見てください。 NFS version 3 以降では O_EXCL をきち
んとサポートしています。テンポラリディレクトリは、いつもローカルに作成
するか、NFS を使ってマウントするなら、常に NFS version 3 以降を使うのが
解りやすい解決策です。 NFS v2 で安全にテンポラリファイルを作成するには
、link(2) と stat(2)を使用しますが、面倒です。これについては、Section
6.10.2.1 に詳しい情報があります。

それはさておき、FreeBSD が最近になって mk*temp()系でファイル名に pid を
付けないようにした点は、注目に値します。pid ではなく、base-62 でエンコ
ードしたランダムな値に完全に置き換えました。このことによって「デフォル
ト」の 6 文字分を使用したテンポラリファイルが大幅に増加しました。つまり
、6 文字を使った mktemp(3)でさえ、頻繁に使用しなければ、名前の推測に対
してかなり (確率的にも) 安全になりました。しかしここでも教えにならうな
ら、彼らが取り組んでいる問題を回避するでしょう。

テンポラリファイルについての情報の多くは、 Kris Kennaway 氏が 2000 年
12月15日に Bugtraq へテンポラリファイルについて投稿した記事 <http://
lwn.net/2000/1221/a/sec-tmp.php3> によっています。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.10.2. ロックをかける

プログラムがあるもの(たとえば、ファイルやデバイス、あるサーバ・プロセス
の存在) に対して、排他的な権限を確保しなければならない状況がよくありま
す。リソースをロックするシステムはどれでも、よくあるロックの問題、つま
りデッドロック(「死の抱擁(deadly embrace)」)やライブロック、そしてプロ
グラムがロックを後片づけしない場合は「取り残された」ロックの解放に対処
しなければいけません。デッドロックは、それぞれのプログラムがリソースが
解放されるのを待って、身動きがとれない場合に発生します。たとえば、デッ
ドロックは、プロセス 1 がリソース A をロックしつつ、リソース B が解放さ
れるのを待っている状態で、プロセス 2 がリソース B をロックしつつ、リソ
ース A が解放されるのを待っている時に起こります。デッドロックの多くは、
複数のリソースをロックするプロセスすべてが、同じ順序付け (たとえば、ロ
ックする名前をアルファベット順にする)でロックを行えば簡単に回避できます
。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.10.2.1. ファイルをロックに使用する

Unix ライクなシステムでリソースをロックするには、これまではファイルを作
ってロックを実現していました。これが非常に移植性がある方法だからです。
またこの方法では、ロックの残骸を簡単に「修復」できます。理由は、管理者
がファイルシステムを見れば、どんなロックが設定してあるのかわかるからで
す。ロックの残骸は、プログラム自身が後片づけに失敗したり(たとえば、クラ
ッシュしたり、誤動作したりした場合)、システム全体がクラッシュした場合に
起こります。これらは「アドバイザリ」(強制(mandatory)ではありません)ロッ
クであることに注意してください。リソースを必要としているプロセスすべて
はこのロックを協調して使わなければいけません。【訳註：ファイルのロック
機能には、強制ロック(mandatory locking)とアドバイザリ・ロック(advisory
locking)があります。違いは、前者はカーネルがプロセスを監視しロック操作
を行うので、プロセス間の依存関係を越えてロックが可能であるのに対して、
後者はプロセス自身がロック操作を行うので、そのプロセスの制御外のものに
対してはロックが無効となります。詳しくは、カーネル付属のドキュメントの
linux/Documentation/mandatory.txt を参照してください】

しかし、避けなければならない落とし穴があります。まず、以前から使われて
いる C プログラムのやり方を使わないようにしてください。その方法では、
create()もしくはそれと等価の open()を呼び出し、open()のモードを
O_WRONLY | O_CREAT | O_TRUNC としてファイルのモードを 0(パーミッション
なし) とします。通常のファイルシステム上で、一般ユーザが行うのであれば
問題はありませんが、ユーザが root の特権を持っている場合には、ファイル
のロックに失敗します。 root はファイルが既に存在していても、常にこの操
作が実行できてしまいます。実際、古い Unix バージョンでは、いにしえのエ
ディタである「ed」がこの特徴的な問題を抱えていました。ときおり、パスワ
ードファイルの一部がユーザのファイルになってしまう現象がありました
[Rochkind 1985, 22]。そうするかわりに、プロセスに使うロックをローカルの
ファイルシステム上に作るなら、open()に O_WRONLY | O_CREAT | O_EXCL フラ
グをつけて使用すべきです (また一方では、パーミッションはつけなければ、
同じユーザの他のプロセスはロックを獲得できません)。 O_EXCL は、正式には
「排他的な」ファイルの作成に使用されます。これはローカルのファイルシス
テム上で root に対しても効果があります[Rochkind 1985, 27]。

次に問題となるのが、ロックファイルを NFS でマウントしたファイルシステム
上に作成する場合です。NFS version 2 が、通常のファイルが持っている機能
を完全にはサポートしていない点が問題です。これは、クライアントが「ロー
カル」にあることを仮定して動作する場合も問題となります。クライアントに
よっては、ローカルでディスクを持たないものやすべてのファイルが NFS 経由
でリモートマウントしているものもあるからです。 open(2) のマニュアルでこ
のケースの扱いを説明しています(root のプログラムの扱いも説明してありま
す)。

"……プログラムが open(2)の O_CREAT と O_EXCL に依存している場合、ロッ
ク機能を動かすと競合状態になることがあります。ロックファイルを使ってア
トミックにファイルロックを実現するには、同じファイルシステム上にユニー
クなファイルを作成し(たとえば、ホスト名や pid を組み合わせて)、link(2)
を使ってそのロックファイルにリンクを張ります。そして stat(2)を使って、
そのユニークなファイルに対してリンク・カウントが 2 まで増えているかをチ
ェックします。link(2) システムコールの返り値は使用しないでください。"

どう考えてもこの解決策では、すべてのプログラムが協調してロックを行わな
いとうまく動作しません。協調していないプログラムが干渉してもうまくあり
ません。特に、ファイルのロックに使っているディレクトリで、ファイルを作
成・削除できるパーミッションを許可してはいけません。

NFS version 3 には O_EXCL モードを open(2)でサポートする機能が追加して
あります。IETF RFC 1813 を見て、特に「CREATE」に対する「モード」値の「
EXCLUSIVE」をよく見てください。残念なことに、現状ではみんながみんな NFS
version 3 以上に移行しているわけではありません。したがって、移植性が必
要なプログラムでは、この機能を頼みにできません。ただし長期的にみれば、
この問題が解決する望みもあります。

ローカルマシン上に存在するデバイスやプロセスをロックするなら、標準的な
約束事を守ってみてください。 Filesystem Hierarchy Standard (FHS)の利用
を推奨します。 Linux システムは広く FHS を参考にしているだけでなく、他
の Unix ライクなシステムのアイディアも盛り込もうとしています。 FHS はフ
ァイルのロックについても説明しており、名前の付け方、置き方、ファイルの
標準的な内容について盛り込んでいます[FHS 1997]。マシンでサーバを 2 つ以
上実行していないかを単に確かめたいなら、通常は /var/run/NAME.pid として
プロセスの識別子を作成し、その中身には pid を入れておきます。同じような
状況で /var/lock のデバイス用ロックファイルのように、ロックファイルを作
成すべきです。この解決方法では、プログラムが予期せずにハングアップする
と、関連したファイルが残ったままになってしまう点が欠点と言えば欠点です
。しかしそれが普通のやり方なので、他のシステムツールを使って簡単に解決
できます。

協調して動作しているプログラムが、ファイルを使ってロックを提供するのに
、同じディレクトリ名を使うだけでなく、実体も同じディレクトリを使用する
のが大切です。ネットワークを利用しているシステムでは、これが問題となり
ます。FHS でははっきりと、/var/run と /var/lock は共有しない、/var/mail
は共有できると言及しています。つまり、単独のマシン上で動作するロックが
必要で、他のマシンから影響を受けないなら、/var/run のような共有しないデ
ィレクトリを使用してください (たとえば、それぞれのマシン独自でサーバが
動作するのを許可したい場合)。しかし、マシンすべてでネットワークにあるフ
ァイルを共有し、ロックに従いたいなら、共有しているディレクトリを使う必
要があります。/var/mail はそんなディレクトリ場所の 1 つです。FHS のセク
ション 2 にこの話題についてのさらに詳しい情報があります。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.10.2.2. ロックを使う他の解決方法

もちろん、ロックするのにファイルを使う必要はありません。ネットワークサ
ーバならこの点についてほとんど悩む必要はありません。あるポートに接続し
てくる動作をロックとして扱うだけでよいからです。つまり、あるポートに既
に接続しているサーバがあれば、もうそれ以上そのポートにサーバは接続でき
なくなります。 

ロックを行う別の解決方法として、POSIX のレコード・ロックがあります。こ
れは fcntl(2) を使って「任意ロック(discretionary lock)」として実装して
いる方法です。これらは任意に使えます。つまりこれらを使うには、ロックを
必要としているプログラムが協調して動作していなければなりません(ファイル
を使ってロックを行うのと同じように)。 POSIX レコード・ロックを推奨する
のには、理由がたくさんあります。 POSIX レコード・ロックは、ほとんどすべ
ての Unix ライクなプラットフォームでサポートしていて(POSIX.1 で公式に推
奨しています)、ファイルの一部(ファイル全体ではなく)をロックでき、読み書
きそれぞれのロックを扱えます。それにも増して、プロセスが死んだとしても
ロックが自動的に解除されます。通常これが望ましい動作です。

強制ロックも使えます。これは System V の強制ロック技術をベースにしてい
ます。ロックされたファイルの setgid ビットは設定してあるが、グループの
実行ビットが設定されていないファイルにだけ適用されます。また、強制ファ
イルロックを許可するには、ファイルシステムをマウントしないといけません
。この場合、read(2) と write(2)それぞれが、ロックする時にチェックされま
す。このやり方はアドバイザリ・ロックよりも徹底しているので、遅くなりま
す。また、強制ロックは、他の Unix ライクなシステムに広く移植されている
わけではありません(Linux と System V ベースのシステムでは利用できますが
、その他は必ずしもそうではありません)。 root 特権を持つプロセスも、強制
ロックで止められますので、サービス拒否攻撃の原因になります。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.11. 信頼できる経路だけ信じること

一般的に、信頼できる経路からの情報(入力や結果)だけを信頼してください。
たとえば、ローカル・ユーザは、getlogin(3) や ttyname(3)が返す情報を制御
できるので、セキュリティ目的では信用してはいけません。

コンピュータで構成されたネットワーク(インターネット全体にも当てはまりま
す) の大部分において、伝送の正当さが証明されていなければ、信頼するに値
しません。たとえば、公開されたインターネット越しにやってくるパケットは
、経路上のどの場所でも見ることも、修正することも可能です。また、新しい
どのパケットも改竄可能です。改竄されたパケットは、送り手や受け手の改竄
した情報(マシンのアドレス(IP)やポート)が入っているかもしれません。した
がって、認証(たとえば、暗号を使って)できない限りは、その情報を第 1 の基
準として、セキュリティ上の判断をしないでください。

つまり特殊な事情がない限り、TCP/IP でユーザ認証を行う場合は、認証の仕組
みとして下記の 2 つの古臭いテクニックを単独では使用しないようにしてくだ
さい。テクニックの 1 つは、ユーザを「あるマシン」に制限する方法で、デー
タパケット中のマシンの「始点」アドレスをチェックします。もう一つの方法
は、送り手が「信頼できる」ポート番号(1024 番以下)の利用を要求することに
よって、アクセス制限をかけます。問題は、多くの環境下において、攻撃者が
これらの値を改竄できる点にあります。

ある環境下では、これらの値(送り手のマシンの IP アドレスやポート番号)の
チェックに意味がある場合もありますので、プログラムでそのようなチェック
をオプションとしてサポートするのは悪くない考えです。たとえば、ファイア
ーウォールの背後にあるシステムで、ファイアーウォールが破られたり、迂回
されたりできない環境です。内部からきていると装っているが、実は外部から
やってきているパケットを抑えているなら、内部からやってきていることにな
っているパケットは、すべて本当に内部からきているといえます。パケットは
、実際にそのマシンがあるとしている場所からきていると確認できない点に注
意してください。したがって、対処できるのは外部からの脅威だけで、内部か
らの脅威には対処できません。しかし、ファイアーウォールがいかれていたり
、別の経路があったり、モバイル用の接続口があったりすると、この前提さえ
も疑わしいものになってしまいます。

問題は、誰かを認証する唯一の手段が、信頼できない情報である点です。信頼
できないネットワーク越しに、信頼できる経路が必要ならば、普通は何らかの
暗号作成技術(最低限でも暗号的に安全なハッシュ技術)の助けが必要となりま
す。暗号アルゴリズムと通信プロトコルについてさらに詳しい情報は、Section
10.5 を見てください。標準的に使われているものの、本来安全でないプロトコ
ル(たとえば ftp とか rlogin)を実行しているなら、デフォルトを安全にして
おき、ドキュメントには前提条件を明記しておいてください。

ドメイン・ネーム・サーバ(DNS)は広くインターネット上で利用されており、コ
ンピュータ名と IP アドレス(数値)の組合せを維持管理しています。「DNS の
逆引き」という方法を使えば、単純なスプーフィング攻撃の一部を排除できま
すし、ホスト名を見つける時にも役立ちます。しかしこのやり方は、認証を決
めるほどの信頼性がありません。つまるところ問題なのは、DNS のリクエスト
が、結局は攻撃者がコントロールしているかもしれないどこかのシステムに対
して送られている可能性がある、という点にあります。したがって、DNS から
得られた結果が正しい入力かどうかを確認する必要があるので、重要なアクセ
ス制御の手段として信用できません。

電子メール(「From」に書いてあるアドレスを含む)も改竄できます。そのよう
な攻撃は、電子署名を使えば防げる場合が多くあります。もっと簡単な防御は
、電子メールにランダムに発生させた値を添付してやりとりする方法です。小
額の金銭取引きもないような、公開メーリングリストへの登録ならば十分利用
できます。

CGI を含むクライアント・サーバモデルでは、クライアント(もしくはクライア
ントとサーバを仲介する何か)が、どんな値も変更できてしまう点に注意してく
ださい。サーバ側はいつもこの点に気をつけていなければなりません。例を挙
げると、いわゆる「隠れフィールド」、クッキー等は、CGI プログラムが値を
受け取る前にクライアント側で値を変更できてしまいます。特に予防処置をと
らない限り、これらは信頼できません。たとえば、隠しフィールドはサーバが
署名をチェックしているなら、クライアントが改竄できないように署名できる
はずです。隠しフィールドは、信頼できるサーバだけが復号できる鍵を使って
暗号化もできます (後者の解決方法は、Kerberos 認証機構が基本的な考えとし
て背景にあります)。 InfoSec labs(http://www.infoseclabs.com/mschff/
mschff.htm)では隠しフィールドや暗号化についてさらに突っ込んだ議論がされ
ています。一般的にクライアント・サーバモデルでは、サーバ側に配慮が必要
なデータをとっておいた方が賢明です。同じ流れで、CGI プログラムで認証を
行う場合、HTTP_REFERER に頼らないようにしてください。これはユーザのブラ
ウザが送ってくるものだからです(Web サーバではありません)。

この問題は、他のデータが参照するデータにも当てはまります。たとえば、
HTML や XML は他のファイル(たとえば、DTD やスタイル・シート) がリモート
にあったとしても、参照ができるようになっています。しかし、外部参照は変
更できてしまうので、ユーザは意図したものとはまったく違ったドキュメント
を見ることになります。スタイル・シートは重要な部分の単語を「白く塗りつ
ぶして」変更できてしまいますので、見た目を汚くしたり、新しいテキストを
挿入できたりしてしまいます。外部の DTD は特定のドキュメントの使用を抑え
たり(DTD の妥当さを崩す宣言を加えることで)、ドキュメントに別のテキスト
を挿入したりして、変更が可能です [St. Laurent 2000]。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.12. 高信頼パス(Trusted Path)を設ける

信頼できる経路(Section 6.11参照)と同列なものに、ユーザが使おうとしてい
るプログラムやシステムが、本当に動作しているのかをユーザに対して保証す
ることが挙げられます。

これまでよくあった例が「ログインしたように見せかける(fake login)」プロ
グラムです。プログラムがシステムのログイン画面のような表示をすれば、表
示しっぱなしにしておけます。ユーザがログインしようとすると、ログインし
たように見せかけるプログラムはユーザのパスワードを横取りし、後で利用し
ます。

この問題に対する解決策が、「高信頼パス」です。高信頼パスは、ユーザにや
りとりしたい相手とやりとりできる確かさを提供するシンプルな仕組みです。
やりとりする情報が何であっても、攻撃者が横取りしたり、変更したりできな
いことを保証します。

パスワードを要求する場合、高信頼パスを用意するように心がけてください。
残念ながら、そこらの Linux ディストリビューションや Unix には、通常のロ
グイン手続きにさえ、高信頼パスが用意されていません。解決方法の 1 つに、
ログインする前に改竄できないキーの押下を要求するという手があります。た
とえば、Windows NT や 2000 のユーザは、ログインする前に「
control-alt-delete」キーを使います。一般的な Windows のプログラムなら、
このキーの組み合わせを横取りできません。このやり方が高信頼パスです。
Linux にもセキュア・アテンション・キー (Secure Attention Key (SAK))
<http://lwn.net/2001/0322/a/SAK.php3> という同等な機能が存在しています
。これによると、「control-alt-pause」キーの使用を推奨しています。あいに
くこのドキュメントを書いている時点では、SAK は完成しているとはいえず、
Lihux ディストリビューションでもサポートしているとは言えません。ローカ
ルで高信頼パスを解決するもう 1 つの方法として、ログイン・プログラムだけ
が動作する独立したディスプレイを管理する手もあります。たとえば、信頼で
きるプログラムだけがキーボードのライト(Num Lock や Caps Lock、 Scroll
Lock を示す LED)を変更できるなら、ログイン・プログラムは動作パタンを表
示して、それが本当のログイン・プログラムであると示せます。残念ながら現
状 Linux の一般ユーザが LED を変更できますので、LED は高信頼パスを確認
するのに利用できません。

情けないことに、ネットワーク・アプリケーションとなるとさらに問題が深刻
になります。高信頼パスを設けるのは、ネットワーク・アプリケーションにと
って意味がありますが、完璧に実行するのはかなり困難です。ネットワーク越
しにパスワードを送る時、せめて信頼できる終端同士間でパスワードを暗号化
してください。こうすれば少なくとも、システムに接続していない攻撃者はパ
スワードを盗聴できません。また少なくとも攻撃がやりづらくなります。実際
にやり取りするための高信頼パスが心配なら、必ずやり取りが暗号化され、認
証済みであるようにしてください(最低限、認証は済ましておくように)。

結果として、ネットワーク・アプリケーションは高信頼パスが十分ではありま
せん。とりわけ Web ベースのアプリケーションではこれが顕著です。よく知ら
れた手法として、Web ブラウザのユーザをだまし、実際は別のところなのに、
ある場所にいると思わせる手があります。たとえば、Felten[1997]では、「Web
スプーフィング」を論じていてます。ユーザがある Web サイトのページを見て
いると信じていても、実はその Web サイトのすべてのページは、攻撃者のサイ
トを経由して見ているというものです (攻撃者は、すべてのトラフィックを監
視して、双方向に送られているどんなデータも変更できます)。これは URL の
書き換えによって実現しています。 URL の書き換えは、他の技術(Javascript
のような)を使えば、ほとんど見えなくすることが可能で、ステータス行やロケ
ーション行その他に形跡をほとんど残しません。詳細はドキュメントを見てく
ださい。他にも URL を隠す技術として、ほとんど使われていない URL の文法
を悪用するものがあります。たとえば、「http://www.ibm.com/
stuff@mysite.com」という URL は、実際には「www.ibm.com/stuff」というユ
ーザ名で「mysite.com」(悪意あるサイトかもしれません)を見る要求を発行し
ます。 URL が長ったらしければ本当のサイト名は表示されず、ユーザはどうし
てやられたかもほとんど気付かないでしょう。さらにもう一つの方法に、サイ
トを作成してその名前をわざと「本当の」サイトと同じような名前にしてしま
う手があります。ユーザは区別がつかないかもしれません。上記すべてのケー
スにおいて、単に行を暗号化しても何にもなりません。攻撃者は何が表示され
るかを完璧に制御できるので、暗号化されたデータでまったく問題がありませ
ん。

これらの問題を対処するのはさらに困難です。現状では、「だまされた」Web
ユーザを防ぐのに有効な技術的解決方法はわかりません。 Web ブラウザの開発
者に対して、そのような「だまし」を簡単に見つけられることで対抗するよう
に働きかけるつもりです。ユーザが正しいサイトに間違いなく接続できること
が重要ならば、単純な手続きで脅威に対抗しなければいけません。たとえば、
ブラウザを落として再起動し、Web のアドレスがとても解りやすくかつ正しく
入力してあるかを必ず確認します(そうすれば入力間違いは起こりえません)。
また、「似たような」発音である DNS 名いくつかの所有権を獲得してしまった
り、その他の DNS 名や実体を探し出して、攻撃者を見つけてしまってもよいで
しょう。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.13. 内部で一貫性をチェックするコードを利用する

プログラムは、呼び出す引数や基本状態の前提が安全なのかチェックしてくだ
さい。 C では、assert(3)のようなマクロが、チェックに役立つと思います。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.14. リソースを自己制御する

ネットワーク・デーモンに対しては、過負荷を抑えたり、制限したりしてくだ
さい。制限値を設定して(setrlimit(2)を使って)、使用するリソースに制限を
かけてください。せめて setrlimit(2)を使って、「core」ファイルができない
ようにしてください。たとえば、デフォルトで Linux は core ファイルを作り
、プログラムが異常な状態で落ちた時に、プログラムすべてのメモリを保存し
ます。しかしそのファイルにはパスワードをはじめ、他にも機密のデータが入
っているかもしれません。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.15. サイトにまたがって存在する悪意あるコンテンツを防ぐ

安全が必要なプログラムには、信頼できないユーザ(攻撃者)からデータを受け
取ったり、そのデータを別のユーザ・アプリケーション(犠牲者)に渡すものが
あります。安全が必要なプログラムが犠牲者を保護してあげなければ、犠牲者
となるアプリケーション(たとえば Web アプリケーション)は、そのデータを処
理して、犠牲者に害を及ぼします。これは、HTML や XML を利用した Web アプ
リケーションではとりわけ良く見られる問題で、「クロスサイト・スクリプテ
ィング」や「悪意ある HTML タグ」、「悪意あるコンテンツ」といういくつか
の呼び方で通っています。このドキュメントでは、この問題を「サイトにまた
がった悪意あるコンテンツ」と呼びます。スクリプトや HTML に問題がしぼら
れているわけではなく、サイトにまたがる性質が問題の根本だからです。この
問題は Web アプリケーションに限ったものではありませんが、Web アプリケー
ションにとっては特別に問題となるので、これからこのドキュメントでは Web
アプリケーションに焦点を当てて論じていきます。まもなく説明して行きます
が、攻撃者は時に犠牲者がデータを安全が必要なプログラムに対して送りつけ
るように仕向ける場合があります。そこで安全が必要なプログラムは、犠牲者
自身を守ってあげなければいけません。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.15.1. 問題を説明する

まずは単純な例からはじめましょう。 Web アプリケーションには、HTML タグ
でユーザからのデータ入力を許可し、後で他の読者に投稿するものがあります
(たとえば、ゲストブックや「読者のコメント」コーナー)。何も防御する手段
を講じなければ、タグを悪意あるユーザが利用して、スクリプトや Java に対
する参照、DHTML タグ、ドキュメントの早すぎる終了(</HTML> を使って)、ば
かげたフォントサイズの要求等を入れ込むことで、他のユーザに攻撃をかけら
れます。この機能は、広範囲に影響を及ぼす可能性があります。たとえば、SSL
で暗号化された接続をさらしてしまったり、制限をかけている Web サイトにク
ライアント経由でアクセスできたり、ドメインベースのセキュリティ・ポリシ
を侵害したり、 Web サイトのページを読めなくしたり、Web サイトのページを
使うに耐えないものにしたり(たとえば、バーナーや不快な素材で困らせる)、
プライバシー侵害を許してしまったり(たとえば、Web のバグを入れ込んで、誰
がどのページを読んだか記録してしまう)、サービス拒否攻撃を行ったり(たと
えば、ウインドウを「無限に」開く)、破壊的な攻撃(ブラウザのスクリプト言
語やバッファオーバーフローのようなセキュリティ上の脆弱性を攻撃する)を行
ったりします。適当な場所に悪意ある FORM タグを組み込むことで、侵入者は
ユーザをだまして、機密情報をさらさせることも可能になります(既存のフォー
ムの動作を変更することで)。これは問題を網羅したリストではありませんが、
事は重大だ、と納得してもらうには十分でしょう。

大部分の「掲示板」で既にこの問題が見つかっています。その内のほとんどで
は、複数人の議論の一部のために用意したテキスト内で対処しています。残念
ながら Web アプリケーションの開発者の大部分は、この問題がごく普通に発生
するものだとは気づいていません。あるユーザから別のユーザに送られるデー
タ値はどれでも、サイトにまたがった悪意ある投稿の原因になりえます。たと
えその場所が、どんな HTML でも置けるという「明らかに疑わしい」場合でな
くてもです。ユーザ自身が悪意あるデータを供給してしまうケースがあります
。つまり、ユーザがだまされて、他のサイト経由でデータを提供してしまう場
合です。ここで HTML リンクでユーザが悪意あるデータを他のサイトに送って
しまう例をあげておきます(CERT から引用しました)。

 <A HREF="http://example.com/comment.cgi?mycomment=<SCRIPT             
 SRC='http://bad-site/badfile'></SCRIPT>"> Click here</A>              

つまり Web アプリケーションは、チェックやフィルタリング、符号化なしでは
入力(フォームデータを含む)を受けられません。 Web アプリケーションは多く
の場合、同じユーザに対してさえ入力したデータを戻せません。それは他のユ
ーザがこっそりとそのデータを提供しているかもしれないからです。そのよう
な構成要素を許可すると、システムに損害を与えるかもしれません。そのシス
テムがユーザを攻撃する経路になってしまう可能性があるからです。さらに悪
いことに、そのような攻撃があなたのシステムからやってきているように見え
てしまうかもしれない点です。

CERT は勧告でこの問題を下記のように説明しています。

   
    Web サイトに不用意に悪意ある HTML タグやスクリプトが入り込む恐れが
    あります。信頼できないソースからの適切でない入力によって、動的に作
    成されたページに入り込みます (CERT Advisory CA-2000-02, Malicious
    HTML Tags Embedded in Client Web Requests <http://www.cert.org/
    advisories/CA-2000-02.html>)。
   
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.15.2. サイトにまたがった悪意あるコンテンツに対処する方法

基本的には、Web アプリケーションの出力がどのユーザから影響を受けても、
フィルタをかけ(この問題を起こす文字列は排除されます)、符号化し(この問題
を起こす文字列は符号化されて問題を防ぎます)、検証する(「安全な」データ
だけが通り抜けます)ことが大切です。これには、URL パラメタやフォームデー
タやクッキー、データベースのクエリ、 CORBA ORB の結果、ファイルに格納さ
れているユーザからのデータを入力として渡ってくる出力すべてを含みます。
フィルタリングと検証は、ほとんどの場合入力時に済ましておいた方が良いの
ですが、符号化は入力の検証と出力の作成時の間のどちらかで行っても良いと
思います。分析することなくデータを通してしまっているなら、入力時にデー
タを符号化した方が良いと思います(やり忘れないでしょうから)。しかしプロ
グラムがそのデータを処理するなら、入力時ではなく出力時に符号化する方が
簡単です。 CERT はフィルタリングと符号化を出力時に行うよう、推奨してい
ます。悪くはないのですが、入力時に行う方が合理的なケースが多々あります
。出力毎にすべてのケースを網羅しなければならないのは非常に問題で、方法
のいかんにかかわらず簡単とはいえません。【訳註：CORBA(Comon Object
Request Broker Architecture)や ORB(Object Request Broker)についてここで
説明するのは難しいので、スキルアップのための分散オブジェクト入門 <http:
//www.atmarkit.co.jp/fjava/rensai2/objetry01/objetry01.html>を見てくだ
さい。わかりやすいと思います】

注意。出力の文字符号化をコントロールできなければ、これらのテクニックが
役立たなくなるケースがかなりあります。そうでなくとも、攻撃者は「予想だ
にしない」文字符号化を行い、ここで論じたテクニックを無効にできます。あ
りがたいことに、コントロールするのは難しくありません。出力の文字符号化
のコントロールについては、 Section 8.5で論じています。

下記のサブセクションでは、まずフィルタをかけたり、符号化したり、検証し
たりする必要がある特殊文字の識別方法について論じ、その後にそれらの文字
のフィルタや符号化もしくはその検証方法について論じます。データを検証す
る一般的な方法を論じたサブセクションはありませんが、入力の検証一般を扱
った Chapter 4や、もし入力が HTML テキストそのものや URI なら Section
4.10を見てください。また、Web アプリケーションは悪意を持ったサイトをま
たがる投稿を受けとれるので、クエリ以外での GET プロトコルの使用は禁止し
てください (Section 4.11を参照してください)。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.15.2.1. 特殊文字を識別する

ここでは、さまざまな環境における特殊文字を載せます。 (この一覧を作成し
た CERT に感謝します)

 ・ ブロックレベルの要素(たとえば、HTML や XML のブロックに含まれるテキ
    ストのパラグラフに登場する)
   
     □ 「<」は、タグを開始するという意味で特殊です。
       
     □ 「&」は、文字エンティティがはじまるという意味で特殊です。
       
     □ "「gt;」は、ブラウザの中に特別扱いをするものがある、ということ
        で特殊です。そのページの著者が、本当は開始の「<" を置くつもりで
        だったのに、間違って省いてしまったという前提です。
       
 ・ 属性値について
   
     □ 二重引用符で囲まれた属性値において、二重引用符は属性値の終端の
        印ということで特殊です。
       
     □ 一重引用符で囲まれた属性値において、一重引用符は属性値の終端の
        印ということで特殊です。 XML では一重引用符は正規ではないことに
        注意してください。一重引用符は使わないよう推奨します。
       
     □ 何も引用符がついていない属性値では、スペースやタブといった空白
        文字が特別扱いになります。 XML では正規のものでないだけでなく、
        さらに他の文字を特別扱いにしてしまうことに注意してください。つ
        まり、動的に値を生成したものを使っているなら、引用符が付かない
        属性を使用するのは賛成できません。
       
     □ 「&」は、文字エンティティの始点になっているため、属性を結合する
        のに使用するということで特殊です。
       
 ・ たとえば URL を例にとると、ある検索エンジンは検索結果のページを表示
    し、そのページ内のリンクをユーザがクリックして検索を再実行できると
    します。この機能は、検索クエリを URL 内に符号化することで実現してい
    ます。実行が完了すると、追加の特殊文字が入り込みます。
   
     □ スペースやタブ、改行は、URL の終端の印となるので特殊です。
       
     □ 「&」は、文字エンティティのはじまりであったり、CGI のパラメタの
        はじまりであったりするということで特殊です。
       
     □ ASCII ではない文字(ISO-8859-1 符号で 128 以上)は URL では認めら
        れていません。したがって URL 内の ASCII ではない文字は特殊です
        。
       
     □ 「%」は入力でフィルタされなければいけません。 HTTP のエスケープ
        シーケンスで符号化されたパラメタが何であっても、サーバ側で使っ
        ているコードへ復号しなければいけません。入力が「%68%65%6C%6C%6F
        」なら、それをフィルタすると Web サイトのページでは「hello」に
        なります。
       
 ・ <SCRIPT> と </SCRIPT> で囲まれた部分にあるセミコロンや括弧、中括弧
    、改行は、既存のスクリプト・タグに直接テキストが挿入できる状況下で
    はフィルタすべきです。 
   
 ・ サーバ側のスクリプトで入力にある感嘆符(!)を出力で二重引用符(") に変
    換するなら、さらに追加でフィルタが必要になります。
   
一般的に HTML や XML においては、アンパサンド(&)は特殊扱いです。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.15.2.2. フィルタリング

これらの特殊文字を扱う方法の一つに、単に特殊文字を削除してしまうという
手があります(通常は入力と出力の間に)。

既に正しい文字を得るために入力を検証しているなら(そうすべきです)、正し
い文字の一覧から特殊文字を取り除くのは簡単です。ここに、Perl で書いたフ
ィルタを載せておきます。このフィルタは正式な文字だけを受け付け、空白以
外のどんな特殊文字も受け付けませんので、引用属性のような部分で使用する
のにかなり有効です。

 # Accept only legal characters:                                       
 $summary =~ tr/A-Za-z0-9\ \.\://dc;                                   

しかし、本当に最低限の文字だけを取り除きたいなら、その文字だけを削除す
るサブルーチンを作っても良いでしょう。

 sub remove_special_chars {                                            
  local($s) = @_;                                                      
  $s =~ s/[\<\>\"\'\%\;\(\)\&\+]//g;                                   
  return $s;                                                           
 }                                                                     
 # Sample use:                                                         
 $data = &remove_special_chars($data);                                 

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.15.2.3. 符号化

特殊文字を削除する別の方法に、特殊文字を符号化して特殊な意味を持たなく
してしまうやり方があります。この方法は、文字にフィルタをかける方法に対
して若干長所があり、特にデータを取りこぼさない点が優れています。ユーザ
から見て、フィルタする過程でデータが「めちゃくちゃ」になるなら、少なく
とも符号化をしておけば、元々送られてきたデータの再構成が可能になります
。

HTML や XML、SGML は皆、アンパサンド(「&」)を本文中で何らかの符号化がは
じまる文字として使っています。この符号化は「HTML エンコード」とよく言わ
れています。これらの文字を符号化するには、ただご自分の環境で特殊文字に
変換してやるだけです。普通これは、「<」が「&lt;」、「>」が「&gt;」、「&
」が「&amp;」、「"」が「&quot;」となります。上記で注意しなければならな
いのは、理屈上は「>」はここで挙げる必要はないのですが、ブラウザには「>
」が悪さをしてしまうものがあるので(「<」を入れてしまう)、ここで挙げるこ
とにしました。二重引用符も多少面倒で、「&quot;」を使う必要があるのは属
性内部だけですが、古いブラウザにはきちんと表示できないものもあります。
さらに複雑になってもかまわないなら、必要に応じて「"」を符号化してもかま
いませんが、単純に符号化する方がやさしいので、ユーザにブラウザのバージ
ョンアップをお願いしてください。

この HTML エンコーディングに対する解決方法は、状況によっては符号化が十
分でないケースがあります。 Section 8.5 で論じていますが、出力文字の符号
化(「文字セット」)を指定してやる必要があります。出力文字の符号化とは別
の符号化を使って文字を符号化しているデータがあるなら、何らかの手を打つ
必要があります。そうしないと出力に整合性がなくなり、正しい結果になりま
せん。また ISO-8859-1 以外で符号化して出力するなら、代わりとなる符号化
が何であれ、ブラウザに特殊文字(「<」のような)の符号化が決して渡らないよ
うにしてください。文字符号化のいくつかのケースでこれが問題になります。
広く使われているものでは、 UTF-7 や UTF-8 がそれに当たります。「代わり
となる」文字の符号化を防ぐ方法についての詳しい情報については、Section
4.8 を見てください。互換性の無い文字符号化を扱う方法の一つに、まず文字
を内部的には ISO 10646 (Unicode と同じ文字値)に変換してしまう方法があり
ます。そうしておいて、数字文字への参照もしくは文字エンティティへの参照
を使って、それらを表示します。

 ・ 数字文字への参照は、「&#D;」のように行います。D は 10 進数です。ま
    た、「&#xH;」もしくは「&#XH;」とします。H は 16 進数です。この数字
    は、ISO 10646 文字コードです(Unicode と同じ文字値です)。つまり &#
    1048; はキリル文字の大文字の「I」です。 SGML 規格(ISO 8879)では 16
    進数系をサポートしていませんので、出力には 10 進数系を使用するよう
    にお薦めします。また SGML の仕様では、ある環境下で後続のセミコロン
    の省略を認めています。実際に、システムの多くでは扱えません。したが
    って、常にセミコロンを後ろに付けるようにしてください。
   
 ・ 文字エンティティへの参照は、同じようなものですが、数字のかわりに覚
    えやすい名前を使っています。たとえば、「&lt;」は < を表わします。
    HTML を書いているなら、 HTML 仕様 <http://www.w3.org> に覚えやすい
    名前をすべて一覧にしてありますので、見てください。
   
どちらの系(数字もしくは文字エンティティ)でもうまくいきます。「<」や「>
」、「&」、「"」への参照は文字エンティティを使うことをお薦めします。理
由はコード(や出力)を見て解りやすいからです。あとはいろいろで、どの系が
全般的に優れているか、はっきりしません。あとで人が手で出力を編集するつ
もりなら、文字エンティティが使えるところには使ってください。さもなけれ
ば、プログラムが簡単になるという理由で、10 進数で文字を参照するようにし
ます。この符号化のプランは、言語によってはまったく役に立ちません(とくに
アジアの言語では)。主に使用するコンテンツがその言語なら、別の文字符号化
(文字セット) を選択し、危ない文字(たとえば「<」)をフィルタした方がよい
かもしれません。危ない文字を認めてしまうような他の符号化は、決してしな
いようにしてください。

URI は独自に符号化の仕組みを用意しています。通常はそれを「URL エンコー
ディング」と呼んでいます。この系では、URL 中に認められない文字をパーセ
ント記号の後に 2 桁の 16 進数値を使って表示します。 ISO 10646(Unicode)
を扱うため、まずコードを UTF-8 に変換してから符号化することが推奨されて
います。 URI の検証については Section 4.10.4 でさらに論じていますので、
見てください。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.16. セマンティック攻撃の裏をかく

「セマンティック攻撃」とは、攻撃者がコンピュータの設備やシステムを利用
して、何らかの方法で犠牲者をだまし、何かをさせてしまうことを指します。
何かをさせるというのは、本来そのコンピュータの設備やシステムが行うよう
に設計されたものとは別のことをしてしまうことを指します。セマンティック
攻撃には、金融詐欺も含まれていて、攻撃者が犠牲者をだまし、攻撃者に大金
を与えてしまいます(たとえば、どこかに投資しているように思わせる)。たと
えば、攻撃者はユーザに信頼できる Web サイトを見ていると信じこませようと
するかもしれません。本当はそうでないのにもかかわらず、です。

セマンテックス攻撃は対処が困難です。理由はコンピュータの正しい操作を悪
用しているからです。セマンテックス攻撃に対処するには、さらにユーザに情
報を与えて気づかせることです。つまり「奇妙な」ことが起こると、ユーザが
もっと情報を持とうとするか、警告が見た目と違う何かが起こっていると知ら
せます。

一例として、URI をあげます。文法上問題無いにもかかわらす、ユーザが取り
違えて考えるかもしれません。ととえば、この URI を見てください。

  http://www.bloomberg.com@www.badguy.com                              

この URI をクリックすると、ユーザは Bloomberg(金融商品ニュースを提供し
ている) に行くと思うかもしれませんが、そのかわりに www.badguy.com に行
ってしまいます (そして、ユーザ名 www.bloomberg.com を www.badguy.com に
渡しますが、 www.badguy.com は都合が良いことにそれを無視するでしょう)。
badguy.com の Web サイトが bloomberg.com のサイトをまねていたなら、ユー
ザは自分が本物のサイトを見ていると、信じてしまうかもしれません(そして攻
撃者がコントロールしている情報を元に、ユーザが投資を決めてしまいます)。
これは普段使われない URI を前提にしています。クリッカブル URI はユーザ
名を設定できますが、普段はそうしていません。このケースの解決には、Web
ブラウザが普段使わない URI を検知するとか、ポップアップで確認を求める
(「ユーザ名 www.bloomberg.com で www.badguy.com にログインしようとして
います。続けますか？」のように)仕掛けを作ることが考えられます。その仕掛
けでユーザが入場を変更できるようになれば、攻撃を防御ができると同時に、
ユーザに対して追加機能を提供できます。

別の例は、同じ綴りで違う意味をもつ言葉(同形異義語)で、特に国間に見られ
る同形異義語です。ある文字はお互いに似て見えますし、同様にやられてしま
う可能性があります。たとえば、0(ゼロ)とO(文字のオー)はお互いに似ていま
すので、ユーザは WWW.BLOOMBERG.COM と WWW.BL00MBERG.COM が違う Web アド
レスであるのがわからないかもしれません。他に見た目が似た文字には、1(数
字の 1)とl(小文字の L)があります。いろいろな国の文字を許可していれば、
事態はさらに悪くなります。たとえば、キリル文字の大部分は、おおよそ英字
と同じように見えますが、コンピュータは違うものとして扱います。現状たい
ていのシステムは、ホスト名としていろいろな国の文字を認めていません。も
っともな理由がない限り、今後ホスト名としてサポートする必要性が広く認め
られるでしょう。解決案の 1 つに、異なる地域を異なる色を使って文字を表示
する方法が取られてきました。つまり、ユーザは視覚的にもっと情報を得ます
。ユーザが URI を見たとすると、おそらく奇妙な色つけに気付くはずです
[Gabrilovich 2002]。しかし、これはセマンティック攻撃の存在を示しはしま
すが、防戦するのは困難です。正確に言えば、コンピュータは正しく動作して
いるのですから。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

6.17. データの種類に気を配る

使用しているデータの種類に注意してください。インタフェースに使われてい
るものについては、特に注意してください。たとえば、「signed」や「
unsigned」の値は、言語の多く(C や C++ のような) で異なった扱いを受けて
います。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

Chapter 7. 他のリソースを利用する場合は慎重に

                                    君侯に依り頼んではならない。人間に 
                                    は救う力はない。                   
                                                                       
                                               旧約聖書詩編 146 章 3 節

実際のところ、本当の意味で自己完結しているプログラムはありません。ほぼ
すべてのプログラムは、リソースを利用するのに他のプログラムを呼び出して
います。たとえば、オペレーティングシステムやソフトウェア・ライブラリが
提供するプログラム等です。時には、この他のリソースに対する呼び出しが、
表に見えなかったり、それなくしては実現できないかなりの数の「隠れた」仕
組みを必要としていたりします。たとえば、動的ライブラリの実現の仕組み等
です。プログラムが信頼している他のリソースについて慎重にならなければい
けないのは明らかです。また、それらに要求を送る方法についても、確認を怠
らないようにしなければいけません。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

7.1. 安全なライブラリ・ルーチンだけを呼び出すこと

セキュリティと抽象化(情報隠蔽)の開発方針及びその再利用が相容れない場合
があります。問題は、高レベルのライブラリルーチンが安全に実装されている
かいないか、わからない点です。仕様書を読んでもわかりません。ある特定の
実装が安全であったとしても、ルーチンの他のバージョンが確実に安全である
とは言えませんし、同じインタフェースが他のプラットフォームでも安全であ
るとは言えません。 

結局のところ、アプリケーションを安全にしなければならないなら、時には自
分自身でライブラリ・ルーチンのバージョンを再実装するはめになります。ラ
イブラリ・ルーチンが必要とするセキュリティ要求に答えることを確認できな
ければ、根本的に解決するのにルーチンを再実装せざるを得ないでしょう。お
気づきになったと思いますが、場合によってはライブラリの実装を修正する必
要があります。しかし、セキュリティ上の弱点を持ったライブラリ・ルーチン
を選択した結果、被害を被るのはユーザです。再実装しなければいけない場合
には、高レベルのインタフェースを使うようにしてください。そうすれば、そ
のインタフェースが安全に使えるシステムでは、高レベルのインタフェースに
切り替えられます。

可能なら、ルーチンが安全かそうでないかのテストをしてください。そして安
全ならば使用するようにしてください。完璧を期すなら、このテストをコンパ
イルやインストール時に実行したらどうでしょうか(たとえば、「autoconf」ス
クリプトの一部として)。ある条件下では、この種の実行時テストは現実的では
ありません。しかし別の条件下では問題の多くを解消してくれます。ライブラ
リの再実装に悩みたくたくなければ、少なくともライブラリが安全であること
を確認し、そうでなかった場合にはインストールを中断してください。そうす
れば、ユーザがうっかり安全でないプログラムをインストールする恐れがなく
なり、問題が何であるかを理解できます。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

7.2. 正しい値でだけ呼び出す

別のプログラムを呼び出す場合はいつでも、常にパラメタとして有効かつ事前
に予想されている値だけを許可していることを確認する必要があります。これ
は言うよりもずっと困難です。と言うのも、さまざまなライブラリ関数やコマ
ンドが、低レベルの関数を意外な方法で呼び出しているかもしれないからです
。たとえば、システムコールの多くは間接的にシェルから実行されます。つま
り文字を渡すのに当たって、シェルのメタキャラクタが危険な結果を引き起こ
す可能性があります。では、ここでメタキャラクタについて論じましょう。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

7.3. メタキャラクタを扱う

システムの多く、たとえばコマンドライン・シェルや SQL インタプリタには、
「メタキャラクタ」が存在します。つまり入力中のある文字が、データとして
解釈されません。そのような文字はコマンドであったり、コマンドや他のデー
タからあるデータを区別するための識別子であったりします。使用しているシ
ステムのインタフェースに言語仕様があるなら、きっとメタキャラクタが含ま
れているはずです。プログラムが他のシステムを実行するようになっていて、
攻撃者がそのようなメタキャラクタを入れ込めるなら、攻撃者は完全にプログ
ラムをコントロールしてしまう、というのがお決まりの結末です。

メタキャラクタの問題で最も広範囲に渡っているのは、シェルのメタキャラク
タです。標準的な Unix ライクなコマンド・シェル(/bin/sh 内蔵の)は、かな
りの数の文字を特別扱いします。これらの文字がシェルに渡ると、エスケープ
していない限り、特別に解釈されます。この事実を悪用して、プログラムがお
かしくさせられてきました。 WWW Security FAQ [Stein 1999, Q37]によれば、
そのようなメタキャラクタは下記のものです。
┌──────────────────────────────────┐
│& ; ` ' \ " | * ? ~ < > ^ ( ) [ ] { } $ \n \r                       │
└──────────────────────────────────┘

注意すべきは、タブや空白文字をエスケープしたい場面がいろいろあるのでは
、という点です。それら(と改行)はパラメタのデフォルトのセパレタだからで
す。セパレタの値は IFS 環境変数を設定して変更できますが、この変数の出所
が信用できないなら、その値を破棄するか、環境変数を処理する過程で何らか
の方法でリセットしてください。

あいにく、完全なリストは現実には存在しません。ここでは疑わしいと思われ
る文字を他にもいくつか挙げておきます。

 ・ 「!」は式ではありません(C では式ですが)。プログラムの返り値をテスト
    するなら、接頭語に ! があると、スクリプトを欺いて実際には成功してい
    ようが、失敗していようが関係なく、何かが失敗したようになります。シ
    ェルには、コマンド履歴にアクセスするのにも「!」を使うものがあります
    。これが現実に問題になる場合があります。 bash ではこれは対話モード
    の場合にだけ発生しますが、tcsh(csh のクローンで、入っている Linux
    ディストリビューションもあります)では「!」をスクリプト内でも使って
    います。
   
 ・ 「#」はコメント文字として使います。この文字以降のテキストは無視され
    ます。
   
 ・ 「-」は間違ってオプションの開始と解釈される恐れがあります(もしくは
    、-- として、すべてのオプション機能を無効にしてしまう)。たとえ、フ
    ァイル名の「中に」入っていたとしても、シェルが事前に空白と認識して
    しまうと困ったことになります。
   
 ・ 「」(空白)や「\t」(タブ)、「\n」(改行)、「\r」(リターン)、「\v」
    (垂直スペース)、「\f」(フォーム・フィード)等の空白文字は、「1 つ」
    のファイル名を複数の引数にしてしまいます。
   
 ・ その他の制御文字(特に NIL)は、シェルの実装によっては問題を起こすか
    もしれません。
   
 ・ 使い方にもよりますが、「.」(「カレントシェルで実行」)や「=」(変数を
    設定) は、厄介な文字です。しかし、これまで見てきた例の限りでは、そ
    の他に(もっと厄介な)セキュリティ上の問題が存在しています。
   
 

シェルのメタキャラクタの影響が著しく広範囲になってしまっているのは、い
くつかの重要なライブラリ・コール、たとえば popen(3)や system(3)、がコマ
ンドシェルを呼び出して実行するからです。つまり、シェルのメタキャラクタ
からも影響を受けています。同様に execlp(3)や execvp(3)もシェルを呼び出
す仕組みになっています。 popen(3)や system(3)、execlp(3)、execvp(3)をま
ったく使用しないように提案しているガイドラインが多く、プロセスを生成す
る場合には execve(3)を C 言語から直接呼び出すように提案しています
[Galvin 1998b]。とにかく、execve(3)が使えるなら、system(3)の使用を避け
てください。system(3)はシェルを使って文字を展開しますので、危険がさらに
広がります。同様に Perl やシェルのバッククォート(`)もコマンドシェルを呼
び出せます。 Perl についての詳しい情報は Section 9.2を見てください。

SQL にもメタキャラクタがありますので、同じような問題が SQL の呼び出しに
も存在しています。 SPI Dynamic's paper ``SQL Injection: Are your Web
Applications Vulnerable?'' <http://www.spidynamics.com/papers/
SQLInjectionWhitePaper.pdf> を見てください。この点についてさらに論じて
いきましょう。 Chapter 4で論じた通り、非常に限定的なパタンを定義して、
パタンにマッチした入力だけを許可するようにしてください。パタンを ^[0-9]
$ もしくは ^[0-9A-Za-z]*$ に制限してあるなら、問題は起こらないでしょう
。 SQL メタキャラクタが入ったデータを扱う必要があるなら、それを何か別の
符号に変換してから(できるだけ早いうちに)、保存してください。たとえば、
HTML エンコードのように(この場合は、アンパサンド文字を符号化してやる必
要があります)。また引用符でユーザの入力すべてを囲んでください。たとえデ
ータが数字であってもです。そうすれば、空白や他の種類のデータは危険では
なくなります。

これらの文字の 1 つでも忘れると災難を被るかもしれません。たとえば、プロ
グラムの多くは、バックスラッシュをシェルのメタキャラクタとして削除して
しまいます [rfp 1999]。 Chapter 4で論じたように、推奨する解決方法は、入
力されたらすぐ、それらの文字をともかくエスケープする方法です。しかし、
はるかに適切な解決方法は、どの文字を許可するのかを自分で特定する方法で
す。そして、それらの文字だけを許可するようにフィルタをかけます。

プログラムには、人間とやり取りするべく設計されたものがたくさんあります
。そのようなプログラムは、「特別な」行為を実現する「エスケープ」コード
があります。もっと一般的(で危険)なエスケープコードの 1 つに、コマンドラ
インを立ち上げるというものがあります。このような「エスケープ」コマンド
が絶対無いようにしてください (さもなければ、そのコマンドが確実に安全で
あるようにしてください)。たとえば、コマンドライン指向のメール・プログラ
ム(mail やmailx のような)では、チルダ(~)をエスケープキャラクタとして使
っています。チルダは多量のコマンドを送る場合に使われてきました。明らか
に無害なコマンド、たとえば、「mail admin < file-from-user」が、結果的に
任意のプログラムを実行するのに利用できます。 vi や emacs、ed のような対
話形式のプログラムは、「エスケープ」する仕組みを持っていて、ユーザがプ
ログラム実行中に任意のシェル・コマンドを走らせられます。呼び出すプログ
ラムのドキュメントをいつも調べて、エスケープする仕組みがないか調査して
ください。他のプログラムを呼び出すなら、利用したいものだけを呼び出すよ
うにするのが適切です。Section 7.4 を見てください。

エスケープコードを回避する問題は、対象範囲が低レベルなハードウェアの部
品やそれをエミュレートするものにまで広がります。モデムにはたいてい「
Hayes」と呼ばれている命令セットが実装してあります。この命令セットが有効
になっていると、遅延を発生させる「+++」というフレーズやそれにともなう別
の遅延によって、そのコマンドに続くテキストがモデムに対するコマンドと解
釈されます。これはサービス拒否攻撃の実行に利用できますし(「ATH0」を送る
ことで、モデムをハングアップさせます)、ユーザを別の所に接続させることさ
え可能です(巧妙な攻撃者なら攻撃者が制御しているマシンを経由するように、
ユーザの接続の経路を変えてしまいます)。ケースをモデムに限定すれば、対処
するのは簡単です(たとえば、モデムの初期化文字列「ATS2-255」を加えておき
ます)。しかしまだ一般的な問題は残っています。低レベルな部品やそのエミュ
レータを制御しているなら、必ずそれらに組み込んであるエスケープコードを
無効にするか、対策を施してください。

「端末」インタフェースでは、既になくなって久しい VT100 のような昔の端末
のエスケープコードを実装しているケースが多くあります。これらコードはと
ても便利で、端末のインタフェースを使って、たとえば文字を太くしたり、フ
ォントの色を変えたり、特定の位置に移動したりできます。しかし、直接端末
のスクリーンに任意の信頼できないデータの送出を認めてはいけません。とい
うのは、コードによっては重大な問題を引き起こすものがあるからです。シス
テムには、キーの割り当てを変更できるものもあります(たとえば、ユーザが「
Enter」もしくはファンクションキーを押すことで、望みのコマンドを送って実
行できます)。中には、コードを送ってスクリーンをクリアしたり、犠牲者とな
る人に実行させたいコマンドを表示できたりするものもあります。表示させて
おいて、画面を「元に戻す」命令を送って、キーが押されるのを待たずに攻撃
者が選んだ命令を実行させてしまいます。これは通常「ページモード・バッフ
ァリング」という機能を使って実現しています。このセキュリティ上の問題は
、仮想 tty(デバイスファイルとして提供されていて、通常は /dev にありま
す)が所有者にだけ書き込みが可能で、他には誰も書き込めないようにすべきで
ある理由になっています。決して「その他の書き込み」パーミッションを設定
してあってはいけません。また、ユーザがグループ(つまり「ユーザプライベー
トグループ」という手法)のメンバーだけでないなら、「グループによる書き込
み」パーミッションも端末に対してかけるべきではありません[Filipski 1986]
。ユーザに対してデータを(擬似)端末で表示しているなら、安全を確認してい
ない限りすべての制御文字(32 よりも小さい値の文字)をフィルタして、ユーザ
に戻すデータから取り除く必要があります。最悪の状況では、タブや改行(おそ
らく復帰改行も)を安全とした上で、残りすべてを排除します。ハイビットが立
っている文字(つまり 127 より大きい値)を扱うにはテクニックを要します。古
いシステムには、ビットが立っていないがごとく実行してしまうものがありま
す。しかし単にそれらの文字をフィルタリングすると、いろいろな国の言葉の
使用を禁じてしまいます。この場合はケースに応じて見ていく必要があります
。

これに関連して、NIL キャラクタ(キャラクタの 0)が意外な影響を及ぼす問題
があげられます。 C や C++ の関数の大部分は、NIL キャラクタが文字列の終
端の印と想定していますが、他の言語(Perl や Ada95 等)の文字列を扱う関数
は NIL を文字列の一部として扱います。ライブラリやカーネルの呼び出しは C
の扱いを踏襲していますので、チェックする内容と実際使用される内容が一致
しません[rfp 1999]。

他のプログラムを呼び出したり、ファイルを参照したりする時には、いつもフ
ルパス (たとえば /usr/bin/sort)のように)で指定するようにしてください。
こうすることで、「間違った」コマンドを呼び出す際に生じるエラーを無くす
だけでなく、PATH 環境変数が間違って設定されていてもエラーを回避できます
。他のファイルの参照についても、「間違った」開始パスを指定した結果生じ
る問題を減らせます。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

7.4. プログラマ向けのインタフェースだけを呼び出す

プログラム向けに用意されているアプリケーション・プログラミング・インタ
フェース (API)だけを呼び出すようにしてください。通常プログラムは他のプ
ログラムを呼び出します。これには、実際に人とやり取りするように設計され
たプログラムも含まれます。しかしプログラムを呼び出すのに、人がやり取り
するようにプログラムを設計するのでは十分ではありません。プログラムのヒ
ューマン・インタフェースがことさら機能豊富であるが故に、完璧に制御する
のが困難になっている点が問題になります。 Section 7.3 で論じたように、対
話的なプログラムには「エスケープ」コードがよくあります。こうなると、攻
撃者が不適切な機能を実行できてしまいます。また、対話的なプログラムは「
多分そうだろう」というデフォルトの設定を実行しようとします。これが期待
しているデフォルトの動作ではないかもしれません。攻撃者は、これにつけ込
む手段を見つけるかもしれません。

通常直接呼び出してはいけないプログラムには、mail や mailx、ed、vi、
emacs があります。最低限これらのプログラムの入力をまずチェックしてから
、呼び出してください。

通常は安全なアクセスをするために、プログラム機能としてパラメタがあった
り、別の API を持っていたり、それらを使わないでプログラム専用のアプリケ
ーションがあったりします。たとえば、テキスト・エディタ(ed や vi、emacs
のような)を呼び出してテキストを編集する代わりに、sed が使えます。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

7.5. システムコールの返り値はすべてチェックする

システムコールでエラー状況を返せるものは、すべてそのエラー状態をチェッ
クする必要があります。まず理由としてあげられるのは、システムコールのほ
とんどすべてが、限られたシステム・リソースを対象としており、そのリソー
スに対してユーザはさまざまな方法で影響を与えられるからです。 setuid や
setgid されたプログラムには、setrlimit(3)や nice(2)のようなシステムコー
ルを呼び出すことで、そのプログラムで使用するリソースの制限ができます。
サーバプログラムを利用する外部のユーザや CGI スクリプトは、同時に多量の
リクエストをサーバに要求してリソースを食い潰せます。エラーを適切に扱え
ないならば、既に述べたフェイル・セーフにしてください。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

7.6. vfork(2)は使わない

Unix ライクなシステムで新しいプロセスを簡単にかつ移植性を持たせて作成す
るには、fork(2) システムコールを使用します。 BSD は vfork(2)と呼ばれる
システムコールを導入して、手法の最適化を図りました。 vfork(2)は fork(2)
とは異なり、execve(2V)を呼び出すか、exit するまでは、子プロセスが親プロ
セスのメモリや制御スレッドを借りています。親プロセスは子プロセスがその
リソースを使っている間、サスペンドします。古い BSD では fork(2)がメモリ
を実際にコピーするのに対して、vfork(2)ではそうしない点が基本です。
Linux ではこの問題はまったく発生しません。なぜなら、Linux は内部ではコ
ピー・オン・ライト方式を使っていて、変更があった時にだけページをコピー
します (実際は、他にもまだコピーしなければいけないテーブルがいくつか存
在します。大部分の動作環境では、このオーバーヘッドはそれほど重くはあり
ません)。にもかかわらず、vfork(2)を使ったプログラムがいくつか存在するの
で、最近になって Linux で BSD の vfork(2) 方式を実装しました(それまでは
、vfork(2) は fork(2)のエイリアスでした)。

vfork(2) にはかなり問題があります。移植性の点からすると、vfork(2)は、親
プロセスに干渉しないようにするのに、実のところかなりトリッキーところが
あります。特に高レベルな言語においてその点が顕著です。「干渉しない」よ
うにするには、実際に生成されるマシンコードに反映する必要があります。ま
た、コンパイラは表に出ない一時的な生成物や予想外の干渉を起こすコードを
構成してしまうケースが多くあります。結論として、vfork(2)を使っているプ
ログラムは、コードが変わったり、コンパイラのバージョンが変わったりする
だけでたいてい機能しなくなります。

Linux システム上の安全が必要なプログラムにとって、これはさらに状況を悪
くします。なぜなら、Linux(少なくともバージョン 2.2 の 2.2.17 まで)は
vfork()の実装に競合状態が起こる脆弱性があるからです。 Linux で特権プロ
セスがユーザのコマンドを実行するのに vfork(2) と execve(2) をペアで使っ
ていると、競合状態が発生します。子プロセスが既にユーザの uid で動作して
いるが、execve(2)はしていないケースです。ユーザが SIGSTOP を含むシグナ
ルをそのプロセスに送れるかもしれません。 vfork(2)方式では、特権を持った
親プロセスも子プロセスと同様にブロックされます。結果的に、特権を持って
いないプロセスが、特権を持ったプロセスを中断させられます。つまりこれは
、特権を持ったプロセスのサービスに対するサービス拒否攻撃になります。少
なくとも FreeBSD と OpenBSD では、このケースに対処するコードが入ってい
ます。この問題に対する脆弱性は、知っている限りありません。 Solar
Designer 氏に感謝しています。彼は 2000 年 10 月 7 日に security-audit
メーリングリストで Linux において、この問題に言及し、証拠を示してくれま
した。

vfork(2)について、結論ははっきりしています。プログラムでは vfork(2)を使
わない、です。こうするのは難しくないはずです。vfork(2)を主に使用するの
は、vfork 方式を必要としている古いプログラムをサポートするためだからで
す。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

7.7. 組込みコンテンツの読み込み時に発生する Web バグに対処する

データフォーマットには、コンテンツへの参照を組み込むめるものもあります
。この参照は、データを見た時に自動的に読み出されます(ユーザが選択するの
を待たずに)。このデータがインターネット経由(全世界から広く)で読み出せる
なら、この機能を使って読者についての知見がなくても、情報を取得できる可
能性があります。また場合によっては、読者に承諾を得ないまま強制的に動作
させることも可能です。このプライバシーに関連する問題を「Web バグ」と呼
ぶ場合があります。

Web バグを使って、ドキュメントの中にあらかじめ参照を埋め込みます。コン
テンツの著者は、誰が、どこで、どんな方法でドキュメントを読んだのか追跡
するのに、これを利用します。また著者は基本的にはどのように「盗み見され
ている」ドキュメントがある人から別の人へ、ある組織から別の組織へとどの
ように渡っていくのかも見張れます。

HTML フォーマットは以前からこの問題を抱えていました。 Privacy
Foundation <http://www.privacyfoundation.org> によれば、

   
    インターネットで広告を扱う会社は、今日 Web バグを Web ページ上で広
    く利用しています。また追跡調査を行うために HTML ベースの電子メール
    でも使われています。それらは、普通大きさが 1 x 1 ピクセルで、スクリ
    ーン上では目に見えず、追跡調査に使われているのを隠しています。しか
    し、それらは(img タグを使った)画像ではありません。他に Web バグを実
    行している HTML タグには、たとえば、フレームやフォーム呼び出し、ス
    クリプトがあります。単独で Web バグを実行すると「盗聴」サイトに対し
    て、読者の IP アドレスや読者が訪れたページ、ブラウザについてのさま
    ざまな情報を提供します。クッキーをあわせて利用すると、読者を個別に
    特定できるようになります。 Web バグについての概要については、 http:
    //www.securityspace.com/s_survey/data/man.200102/webbug.html で見ら
    れます。
   
もっと心配なのは、他のドキュメントのフォーマットがそのような機能も持っ
ているように見える点です。 Web サイトにある HTML を Web ブラウザで見る
時に、誰がデータをブラウジングしているかという情報を取得する方法が別に
あります。しかし、電子メールのような別のフォーマットのドキュメントを見
る時に、ドキュメントを読んだだけで監視されてしまうと想像できるユーザは
ほとんどいません。たとえば、最近になって Microsoft Word は Web バグのサ
ポートを決定しました。 the Privacy Foundation advisory for more
information <http://www.privacyfoundation.org/advisories/
advWordBugs.html> を見てください。その勧告で言及しているように、最近の
バージョンの Microsoft Excel や Microsoft Power Point も盗み見できます
。場合によっては、クッキーはさらに情報を取得するのに利用できます。

Web バグは、おもにファイルフォーマットの設計に当たって問題となります。
ユーザがプライバシーを大事にするなら、おそらくファイルを含む自動的なダ
ウンロードに制限をかけたくなるしょう。ファイル自体をダウンロードする場
合(つまり、Web ブラウザ経由で)は、例外の 1 つです。他のファイルを同じ場
所から同じ時間にダウンロードしても、ユーザにはほとんど関係ありません。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

7.8. 秘密にしたい情報は隠す

秘密にしたい情報は、詮索好きな目から見えないようにすべきです。入力であ
っても出力であっても、システムに保存されている時にはそうすべきです。秘
密にしたい情報には、クレジットカードの番号や貯金の残高、自宅の住所等が
必ず含まれます。また、アプリケーションは名前や電子メールのアドレス他の
プライベートな情報をたくさん扱っています。 

Web ベースのアプリケーションは、ユーザとの通信に秘密にしたい情報がある
なら、すべて暗号化する必要があります。普通は、「https」プロトコル(HTTP
を SSL や TLS にのせている)を使います。 HTTP 1.1 の規格書(IETF RFC 2616
セクション 15.1.3)によれば、HTTP プロトコルを使ってサービスを提供してい
る著者は、GET をベースにしたフォームを秘密にしたいデータの登録に使用す
べきではないとしています。そうすると、このデータがリクエストした URI に
符号化して入ってしまうからです。既存のサーバやプロクシ、ユーザ側のエー
ジェントの多くは、リクエストした URI をどこかに記録し、この記録が第三者
から見えてしまうかもしれません。 GET のかわりに、この目的に向いている
POST ベースで登録を使ってください。 

秘密扱いのデータを扱うデータベースでは、記憶装置(ディスク上のファイル
等) も暗号化しておくべきです。そのような暗号化をしても、攻撃者が安全が
必要なアプリケーションを破壊する行為を防げませんし、当然ながらアプリケ
ーションは、暗号化したデータにアクセスする何らかの手段も用意しなければ
なりません。しかし、データが入ったバックアップ用のディスクをどうにか得
ようとする攻撃者に対しては、防御になります。しかしデータの復号に使用す
る鍵を得ようとする攻撃に対しては、効果がありません。また、攻撃者がアプ
リケーションにまんまと侵入できなければ防御になります。しかし、関連して
いるシステムの一部に侵入できれば、保管してあるデータを見るのには十分で
す。この場合も、攻撃者は暗号化アルゴリズムを破らなければ、データを取得
できません。データが不用意に移動してしまうケースがたくさんあります(たと
えば core ファイル) が、これも防げます。しかし注目すべきなのは、思った
ほどこれが強力な防御にはならない点です。サーバ自身がやられてしまう可能
性があるからです。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

Chapter 8. 情報はえりすぐってフィードバックする

                                    愚か者にはその無知にふさわしい答え 
                                    をするなあなたが彼に似た者とならぬ 
                                    ために。                           
                                                                       
                                                旧約聖書箴言 26 章 4 節
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

8.1. フィードバックは最小限に

信頼できないユーザに対しては、多くの情報を提供しないようにしてください
。ただ成功したか、失敗したかを教えて、失敗しても失敗したと言うだけにし
て、なぜ失敗したかについては、できるだけ教えないようにしてください。詳
細な情報はユーザの痕跡を検証したログに保存してください。たとえば、

 ・ プログラムに何らかのユーザ認証が必要な場合(たとえばネットワークサー
    バやログイン・プログラムを作成している)、認証前の段階では、ユーザに
    はできるだけ情報を与えないようにしてください。特に認証前にプログラ
    ムのバージョンナンバーを漏らすことがないようにしてください。そうし
    ないと、特定のバージョンのプログラムに穴があることがわかってしまっ
    た場合、そのバージョンからアップグレードしないユーザが攻撃者にみす
    みす穴を教えてしまうことになってしまいます。
   
 ・ プログラムがパスワードを要求する場合、入力を表示してはいけません。
    パスワードがばれる原因の 1 つになってしまいます。
   
 

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

8.2. コメントはいれない

情報を返す時には、情報を受け取るユーザにコメントを見せてもよいと望んで
いない限りは、「コメント」を入れてはいけません。ファイル(HTML のような)
を作成する Web アプリケーションにこの問題は顕著です。 Web アプリケーシ
ョンのプログラマは、自分の作品にコメントを入れたがり(これは良いことで
す)ますが、コード中にただコメントを残すだけでなく、作成したファイル (普
通は HTML か XML)の一部として含めます。それがユーザに返されます。このコ
メントが時にそのシステムがどのように動作しているかを見抜く手段を提供し
、攻撃者を助けることになります。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

8.3. 出力が溢れたり、反応が遅い場合も対処する

安全が求められるプログラムで、ユーザへ出力する過程を詰まらせたり、出力
の反応を遅くさせられることが、ユーザにとって可能かもしれません。たとえ
ば、Web ブラウザは故意に TCP/IP の経路を切断したり、反応速度を遅くした
りできます。そのようなケースに対しても、安全が求められるプログラムは対
応するべきです。特にロックはすみやかに外すようにすべきです(できれば反応
を返す前に)。そうすれば、サービス拒否攻撃の隙ができるようなことはありま
せん。ネットワークへの書き込み要求は、常にタイムアウトを設定すべきです
。 

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

8.4. データフォーマットを制御する(「書式文字列」)

コンピュータ言語における出力ルーチンは、書式を制御するパラメタを持って
いるケースが多くあります。 C で最もよく知られた例が printf()系のルーチ
ン(printf()や sprintf()、 snprintf()、fprintf()等)です。 C での他の例は
syslog()(システムのログ情報を書く)や setproctitle() (プロセス識別子の情
報を文字で表示するのに使用)です。関数に付いた名前は、「err」や「warn」
ではじまったり、「log」が含まれていたり、「printf」で終わったりしている
点に注意する価値はあります。 Python は「%」演算子を持っていて、文字列に
あると書式を同じように制御します。プログラムやライブラリの多くは、フォ
ーマット機能を定義していて、普通は組み込みルーチンを呼び出し、さらに処
理を加えます(たとえば、glib の g_snprintf()ルーチンのように)。

意外にも、これらのフォーマット機能を見くびっているように思える方々がた
くさんいて、信頼できないユーザからのデータを、書式パラメタとして利用し
ています。フィルタをかけることなしには、信頼できないユーザからのデータ
を書式パラメタとして使用しないでください。例としてぴったりなのが下記で
す。

  /* Wrong ways: */                                                    
  printf(string_from_untrusted_user);                                  
  /* Right ways: */                                                    
  printf("%s", string_from_untrusted_user); /* safe */                 
  fputs(string_from_untrusted_user); /* better for simple strings */   

さもなければ、攻撃者は書式文字列を慎重に選んで、ありとあらゆる悪さを行
います。 C の printf() が良い例です。 printf()を使って、ユーザが制御し
ている書式文字列を悪用する方法はたくさんあります。これらの方法には、長
い書式文字列によるバッファオーバーラン(攻撃者がプログラムを完全にコント
ロールできてしまいます)や認められていないパラメタを使用する変換規則(予
想外のデータを挿入する)、まったく予想できない結果になる値を作りだすフォ
ーマット等があります(不適切なデータを前後に入れて、後で利用する時に問題
を起こす)。特にひどいケースは、printf の %n の変換規則です。この規則で
は、多量の文字をポインタ引数にあるだけ書き込みます。これを使うと、攻撃
者は書き込もうとした値に上書きできてしまいます。また、攻撃者はほとんど
任意の場所に上書きさえ可能です。それは本来は渡されなかった「パラメタ」
を指定できるからです。これらの攻撃について詳しく論じた資料はたくさんあ
ります。たとえば、 Avoiding security holes when developing an
application - Part 4: format strings <http://www-syntim.inria.fr/
fractales/Staff/Raynal/LinuxMag/SecProg/Art4/index.html> がその 1 つで
す。

結果をユーザに返すケースが多いので、この攻撃はスタックについての内部情
報をさらす場合にも使われます。この情報は、StackGuard のようなスタックを
守るシステムを回避するのにも利用できます。StackGuard は定数の「canary」
値を用いて攻撃を検知します。しかしスタックの内容が表示できるなら、現在
の canary の値がさらされて、攻撃を受けやすくなります。

書式文字列は、ほとんどいつも文字列定数のはずですが、国際化を見つけ出す
関数呼び出し(たとえば、gettext の _())を含むこともあります。この検索を
行うには、プログラムが制御する値に制約を設けなければなりません。つまり
ユーザは、プログラムが管理しているメッセージファイルからしか選択できな
いようにしなければいけません。ユーザのデータには、使用前にフィルタをか
けられます(書式文字列として正しい文字、たとえば [A-Za-z0-9] のような文
字をリストアップしてフィルタを設計します)。しかし、問題を防ぐのに、普通
はもっと簡単で良い方法があります。それは、書式文字列を固定するか、fputs
()を使用するかです。先に「出力」の問題としてリストアップしましたが、内
部的に出力以前のプログラムに対しても問題が発生します(出力ルーチンはファ
イルに保存しているかもしれず、 snprintf()を使って、内的な状態の生成さえ
しているかもしれないからです)。

入力フォーマットの問題によって、セキュリティ上の問題が発生するのは、あ
ながちないともいえません。CERT Advisory CA-2000-13 を見れば、この弱点を
利用した攻撃の例が載っています。これらの問題がいかにやられやすいのかに
ついて、さらに詳しい情報は、 Pascal Bouchareine 氏の電子メールで、タイ
トルが「[Paper] Format bugs」にあります。これが書かれたのは 2000 年 7
月 18 日です Bugtraq <http://www.securityfocus.com>。 2000 年 12 月現在
、gcc コンパイラの開発版では、安全でない書式文字列に対しての警告メッセ
ージをサポートしています。開発者がこれらの問題を回避できるように支援す
る試みです。

もちろんこれは国際化の検索が実際のところ安全かどうか、という疑問をはぐ
らかしています。自分で国際化の検索ルーチンを作成しているなら、信頼でき
ないユーザには、正しいロカールだけが指定可能で、勝手なパスを指定するよ
うな、何か違うものを指定できないようにしてください。

信頼できる相手に対するものであっても、国際化によって作られた文字列には
制限をかけなければいけません。これは明白です。そうしないと、攻撃者はこ
の機能を利用して書式文字列の弱点に突け込みます。これは C や C++ のプロ
グラムに顕著です。この点は Bugtraq で話題になってきました(たとえば、
John Levon 氏が 2000 年 7 月 26 日に Bugtraq に投稿したものを見てくださ
い)。さらなる情報は、ユーザに許可する選択は、正しい言語の値だけにするこ
とを論じた Section 4.7.3 を見てください。

プログラミング上のバグであるとはいえ、いろいろな国々でさまざまな方法で
数字を表記している点に触れるのは意味があります。特にピリオド(.)とカンマ
(,)が、整数と端数部分を区切るのに使われている点に対して。データを保存し
たり、読み込んだりするなら、使用中のロカールがデータの取り扱いに絶対干
渉しないようにしなければなりません。そうしなければ、フランス語ユーザは
英語ユーザとデータを交換できないかもしれません。理由は、保存されたり、
取り出したりしたデータは違う区切りを使っているかもしれないからです。セ
キュリティ上の問題としてこれが利用されるのかどうかは定かではありません
が、ないとも思えません。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

8.5. 出力時に文字符号化を制御する

一般的に、安全が必要なプログラムでは、そのプログラムが決めた前提条件と
クライアントが同期していなければいけません。よくある問題の 1 つとして、
文字を出力する際に符号化指定を行わないと、Web アプリケーションに支障が
でる点が挙げられます。すべてのデータが信頼できる元からくる場合はかまい
ません。しかし、信頼できない元からもデータがくるなら、信頼できない元が
安全が必要なプログラムの予期できない別の符号化を使って、データを偽るか
もしれません。これがサイトにまたがる悪意ある攻撃のきっかけになります。
詳しくは、 Section 4.9 を見てください。

CERT's tech tip on malicious code mitigation <http://www.cert.org/
tech_tips/malicious_code_mitigation.html> でこの文字符号化を指定しない
問題についてかなりわかりやすく解説していますので、ここで引用します。

   
    Web ページの中には、文字符号化(HTTP の「charset」パラメタ)を定義し
    ていないところがたくさんあります。 HTML や HTTP の初期バージョンで
    は、文字符号化が定義されていないと、デフォルトで ISO-8859-1 である
    と仮定していました。実際に、ブラウザのデフォルトはさまざまだったの
    で、デフォルトを ISO-8859-1 としてしまうのには無理がありました。
    HTML version 4 では、文字符号化を指定していなければ、どの符号化を使
    ってもかまわないことになりました。
   
    Web サーバがどの文字符号化を使うのか指定していないと、どの文字が特
    殊文字なのかがわかりません。文字符号化を指定していない Web ページは
    、たいていの場合うまく動作します。それは文字集合のほとんどが、128
    以下のバイト値に同じ文字を割り当てているからです。しかし、128 以上
    の値のどれが特殊文字なのでしょうか。 16 ビットの文字符号化方式には
    、「<」のような特殊文字を表示するのに、追加で複数バイトを使っている
    ものもあります。ブラウザには、これを別の符号化として認識し、動作す
    るものもあります。これは「正しい」動作なのですが、悪意あるスクリプ
    トを使った攻撃が、防ぎづらくなってしまっています。サーバはどのバイ
    トシーケンスが特殊文字を現すのか、単純には判断できなくなります。
   
    たとえば、UTF-7 は「<」と「>」に対して、異なる符号化を提供していま
    す。またよく使われているブラウザのいくつかは、これらをタグの開始と
    終了として認識するものもあります。これはブラウザのバグではありませ
    ん。文字符号化が本当に UTF-7 なら、これは正しい動作です。問題は、ブ
    ラウザとサーバが符号化で同期がとれていない状況に陥る可能性がある点
    です。
   
この問題を説明するのは厄介ですが、有り難いことに、HTML での解決策は簡単
です。 HTML ヘッダに文字セットを下記の例のように設定するだけです。

<HTML>                                                                 
<HEAD>                                                                 
<META http-equiv="Content-Type"                                        
content="text/html; charset=ISO-8859-1">                               
<TITLE>HTML SAMPLE</TITLE>                                             
</HEAD>                                                                
<BODY>                                                                 
<P>This is a sample HTML page                                          
</BODY>                                                                
</HTML>                                                                

 

技術的な観点からすると、文字符号化を HTTP プロトコルの出力の一部として
設定する方が、さらに良い解決策です。しかし、これを難しくしているライブ
ラリが存在します。この解決策は技術的には優れています。クライアントに強
制的にヘッダーを調べさせ、ヘッダー中にあるMETA 情報を読んでわかる文字符
号化を判定する必要がないからです。もちろん、現実的には上記のような META
情報を読めなかったり、正しく扱えなかったりするブラウザは、市場では受け
入れられていません。しかしそれは別問題です。いずれにしても、サーバが
HTTP プロトコルの一部として「文字セット」に適切な値を設定して送り出す必
要があります。残念ながら、この(技術的には優れた)解決方法を心からお薦め
できません。それは、古い HTTP/1.0 対応のクライアントには、明示的に指定
してある charset パラメタを適切に扱えないものがあるからです。 HTTP/1.1
の仕様では、クライアントがこのパラメタに従うように定めていますが、それ
を実現するのは、ははなはだ疑わしいと思います。おそらく、正しい文字符号
化の利用を強制する手段として、その仕様を唯一の方法としてではなく、追加
の方法として使うことになるでしょう。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

8.6. Include ファイルや設定ファイルへのアクセスを防ぐ

Web ベースのアプリケーションを開発する時に、ユーザにプログラムの
include ファイルや設定ファイルへのアクセス(読み込み)を認めてはいけませ
ん。このデータは、システムに侵入するのに十分な情報(たとえば、パスワー
ド)を提供するかもしれません。このガイドラインは、ケースによって他の種類
のアプリケーションにも適用できることを覚えておいてください。このガイド
ラインを実行するのに、必要な作業がいくつかあります。

 ・ プログラムの include ファイルもしくはその設定ファイルは、Web のドキ
    ュメントルート外に置いてください(つまり、Web サーバはそれらのファイ
    ルを絶対外部に出しません)。
   
 ・ include ファイルがテキストファイルとして外部に出さないように、Web
    サーバを設定してください。たとえば、Apache を使っているなら、.inc
    ファイル用にハンドラかアクションを追加できます。
   
 ・ include ファイルは保護されたディレクトリ(.htaccess を使って) に置い
    てください。その上で、外部に出ないファイルとして設定してください。
   
 ・ ファイルに対してフィルタを使ってアクセスを拒否するようにしてくださ
    い。 Apache なら、下記で実現できます。
   
     <Files ~ "\.phpincludes">                                  
        Order allow,deny                                        
        Deny from all                                           
     </Files>                                                   
   
    正規表現をフルに活用してファイル名をマッチさせる必要があるなら、
    Apache では FilesMatch 命令を使えば実現できます。
   
 ・ include ファイルが正規のスクリプトで、それをサーバが解析するなら、
    ユーザが渡してくるパラメタでは絶対動作しないようにしてください。あ
    わせて必ず安全に設計してください。
   
これらの解決方法では、ファイルが置いてあるディレクトリを誰もが読める場
合、ユーザのアクセスを防御できません。ファイルのパーミッションを変更し
て、Web サーバの uid もしくは gid を持っている者だけが読めるようにして
ください。しかしユーザが Web サーバで自分のスクリプトを実行できる(ユー
ザがファイルにアクセスするスクリプトを書ける)のなら、この方法ではうまく
ありません。そもそも、サイトをホスティングしているサーバが信頼できない
人間と共有ならば、システムを安全にするのは困難です。解決方法の 1 つは、
Web サービスを提供するプログラムを複数立ち上げ、それぞれパーミッション
を別にすることです。この方法でさらに安全にはなりますが、実際骨が折れる
作業です。また別の解決方法として、自分の uid や gid だけが対象ファイル
を読めるように設定し、サーバがそのスクリプトを「自分」のパーミッション
で実行するようにします。後者の方法はそれ自身問題があります。サーバのあ
る部分に root の権限が必要となるからです。そうなると、スクリプトに必要
以上のパーミッションが必要となるかもしれません。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

Chapter 9. 言語固有の問題

                                    世にはいろいろな種類の言葉があり、 
                                    どれ一つ意味を持たないものはありま 
                                    せん。                             
                                                                       
                                    新約聖書コリントの信徒への手紙一 14
                                                              章 10 節)

言語には固有の問題がたくさんあります。下記にその問題の多くを要約して挙
げておきます。

 ・ 関連する警告と実際に利用できる防御機構をすべて有効にしてください。
    コンパイル言語では、コンパイル時と実行時の両方が対象になります。一
    般的にセキュリティに関連しているプログラムでは、警告をすべて有効に
    して、きちんとコンパイルすべきです。
   
 ・ 「セーフ・モード」(つまり、実行動作に制約をかけられるモード)が利用
    できるなら、そうしてください。インタプリタ言語の多くは、そのような
    モードを用意しています。一般的に、セーフ・モードに頼って、それだけ
    で防御を行ってはいけません。セーフ・モードを持っている言語の大部分
    は、言語のセキュリティを十分に分析しているとは言えません。そうなる
    と、そこを狙ってさまざまな手段を見つけ出してしまうのが通例です。し
    かしコードを書くに当たっては、コードがセーフ・モードを使わなくても
    安全であるようにし、さらにセーフ・モードをかけて、最終的には何重に
    も防御をかかるようにします(おおかた、攻撃者はアプリケーションのコー
    ドとセーフ・モード両者を壊さなければならなくなります)。 
   
 ・ 言語に含まれている危険で古臭い操作は避けてください。「危険」とは、
    操作を正しく行うのが難しいものを指します。たとえば、言語の多くには
    「不思議な」機構や機能があります。つまり、「正しい」動作を推測して
    、試行錯誤して使用するものです。一般的にはこれらは避けるべきです。
    攻撃者が試行錯誤してそれにつけこみ、予測できない何か危険なことがで
    きるかもしれないからです。よく起るエラーに、「オフ・バイ・ワン
    (off-by-one)」エラーがあります。これは、境界値が 1 つずれることで、
    結果的にエラーとなる脆弱性です。普通、オフ・バイ・ワンエラーの発生
    が最小限になるようにコードを書いてください。言語に標準規約があるな
    ら(たとえば、ループの書き方)、それに従ってください。
   
 ・ 言語の基盤となる部分(たとえば、ランタイム・ライブラリ)が利用でき、
    それが安全であるかを確認してください。
   
 ・ 文字列のガーベジ・コレクションを自動的に行う言語において、機密デー
    タ(特に秘密鍵やパスワード)を慎重にすぐ削除してください。
   
 ・ 自分が使用している操作方法を正確に理解しておいてください。ドキュメ
    ントにある操作方法それぞれを調べてください。関連する可能性がないと
    確認できない限り、返り値は無視しないでください。「signed」の値と「
    unsigned」の値の違いを無視しないでください。例外をサポートしていな
    い C のような言語では特に困難ですが、方法はあります。
   
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

9.1. C と C++

C と C++ プログラムに存在する最大のセキュリティ上の問題の 1 つは、バッ
ファオーバーフローです。詳しくは Chapter 5 を見てください。 C はさらに
例外をサポートしていないという弱点を持っていて、重大なエラーを無視して
、安直にプログラムをコーディングできます。

C や C++ には他にも問題があります。それは、開発者が自分でメモリ管理をし
なければならない点です(たとえば、malloc()や alloc()、free()、new、free)
。メモリ管理に失敗すると、結果としてセキュリティ上の弱点になるかもしれ
ません。もっと深刻な問題は、プログラムが開放してはいけないメモリを間違
って開放できる点です(つまり、C++ で malloc() と new 命令を混ぜて使うと
、不正な命令を利用していることになります)。こうなると、場合によっては
GNU/Linux システムのように、すぐクラッシュするケースもあります。またあ
るケースでは攻撃者がそこにつけ込んで、勝手にコードを実行させてしまうか
もしれません。たとえば、2001 年 3 月 11 日に zlib ライブラリでこの問題
が発生しているとアナウンスされ、それを使っている多くのプログラムが影響
を受けました。したがって、GNU/Linux 上でプログラムをテストする時には、
MALLOC_CHECK_ 環境変数に 1 もしくは 2 を設定すべきです。そして、自分の
プログラムを実行するのに当たっては、0、1、2 いずれかに設定するのを検討
してもよいと思います。この設定をする理由については、GNU/Linux の malloc
(3) に説明があります。

   
    最近のバージョンの Linux libc(5.4.23 以降)と GNU libc(2.x)では、
    malloc の動作が、環境変数によって調整できる実装になっています。
    MALLOC_CHECK_ が設定されていると、専用の(非効率な)実装が用いられて
    、単純なエラーには耐えられるようになります。単純なエラーとは、free
    ()を同じ引き数で 2 度呼び出してしまったり、 1 バイトだけ余計に取っ
    たり(オフ・バイ・ワンのバグ)する等です。しかし、これらのエラーすべ
    てを防げるわけではなく、その場合にはメモリリークが発生します。
    MALLOC_CHECK_ を 0 に設定すると、ヒープの破壊に対して警告を出さずに
    、そのままにしておきます。1 に設定すると、診断メッセージが標準エラ
    ー出力に表示されます。 2 に設定すると、ただちに abort() が呼び出さ
    れます。プロセスが実際にクラッシュするのがずっと後になり、クラッシ
    ュした時点で本当の原因を探し出すのが非常に困難な場合には、これが役
    立ちます。 
   
未使用のメモリを開放しないと(たとえば、free()を使って)、未使用のメモリ
がたまってしまいます。未使用のメモリがたまり過ぎると、プログラムが動作
停止してしまうかもしれません。未使用のメモリが攻撃者に利用され、サービ
ス拒否を起こす結果になる可能性もあります。理屈上では、攻撃者がメモリを
フラグメント化して、サービス拒否を起こせます。しかし普通これはかなり非
現実的で、攻撃としては危険性が低くなります。

型宣言をする時にはできるだけ厳密にしてください。利用できるなら「enum」
を使って、列挙型の値を定義してください(特別な値を持った「char」や「int
」を使うのではなく)。 enum は特に switch 文の値で役に立ちます。コンパイ
ラが、正しい値を適用しているかどうかを判定してくれます。値が負にならな
ければ、「unsigned」を使用するのが適切です。

C や C++ でやっかいなのは、文字型である「char」が signed もしくは
unsigned どちらにもなる点です(コンパイラやマシンによって違います)。
signed char にハイビットを設定し、整数として保存すると負になります。こ
れが脆弱性になるケースがあります。一般的には、char や signed char のか
わりに「unsigned char」を使って、バッファやポインタに利用してください。
そして、127(0x7f)以上の値になるかもしれない文字データを扱うなら、キャス
トしてください。

C と C++ における型チェックのサポートは明らかにいい加減です。しかし、少
なくともチェックのレベルを上げれば、間違いのいくつかは自動的に検知でき
ます。コンパイラの警告をできるだけ有効にしてコードを修正し、警告が何も
出ないようにコンパイルしてください。必ず ANSI のプロトタイプ宣言を独立
したヘッダファイル (.h)に入れて利用し、関数呼び出しすべてが必ず正確な型
になっているようにしてください。 gcc を使って C や C++ をコンパイルする
なら、コンパイル時のフラグとして、少なくとも下記を設定してください(たく
さんの警告メッセージが有効になります)。また、警告はすべて取り除くように
してください(警告には、データフロー分析を行って、高レベルの最適化を図っ
た時にだけ検知されるものがあります。その場合、-O2 が使われていることを
覚えておいてください)。
┌──────────────────────────────────┐
│gcc -Wall -Wpointer-arith -Wstrict-prototypes -O2                   │
└──────────────────────────────────┘
「-W -pedantic」としてもよいと思います。

C や C++ コンパイラが、不正な書式文字列を検出できるケースが多々あります
。たとえば gcc では、__attribute__()機能(C 拡張機能の 1 つ)を使って、不
正な書式文字列への警告が可能になり、該当する関数に印をつけます。また、
この機能を使ったとしても、コードの互換性は無くなりません。ここでは、ヘ
ッダファイル(.h)に何を入れるのかの例を挙げておきます。

 /* in header.h */                                                     
 #ifndef __GNUC__                                                      
 #  define __attribute__(x) /*nothing*/                                
 #endif                                                                
                                                                       
 extern void logprintf(const char *format, ...)                        
    __attribute__((format(printf,1,2)));                               
 extern void logprintva(const char *format, va_list args)              
    __attribute__((format(printf,1,0)));                               

「format」属性は、「printf」と「scanf」で利用できます。その後に続く数字
は書式文字列のパラメタ数と最初の可変引数パラメタ(個々に)です。この点に
ついては、GNU のドキュメントで解りやすく解説しています。他の機能として
、__attribute__ には「noreturn」や「const」等があります。

C や C++ の開発者がよく起こすエラーを無くしましょう。たとえば、「==」を
使うつもりで「=」を使わないよう、注意してください。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

9.2. Perl

Perl プログラマは、まず perlsec(1)を読んだ方が良いでしょう。この man に
は安全が求められる Perl プログラムの書き方に関して、課題がたくさん載っ
ています。特に perlsec(1)では、「汚染(taint)」モードについて説明してい
ます。安全性が必要なプログラムは、このモードを使用すべきです。実もしく
は実効ユーザ id やグループ id が違っていれば、自動的に汚染モードが有効
になります。もしくは、-T をコマンドラインに指定して有効にできます(たと
えば CGI スクリプトのように、誰かの代わりに実行するなら、後者を使ってく
ださい)。汚染モードは、さまざまなチェックを有効にします。たとえば、ディ
レクトリのパスのチェックをして、他のユーザが書き込めないようになってい
るかをチェックします。

しかし、汚染モードの効果が最もはっきり現れるのは、誤ってプログラム外の
何かに影響を与えてしまわないように、プログラム外部からくるデータを使わ
ない方が良い場合です。汚染モードでは、外部から得た入力は「汚染された」
ものとして印が付けられます。外部からの入力には、コマンドラインの引数や
環境変数、ロカール情報(perllocale(1) 参照)、システムコールの結果
(readdir や readlink、getpw* の gecos フィールドの呼出し)、ファイル入力
すべてがこれに該当します。汚染されたデータは直接利用されません。また、
間接的にサブシェルから呼び出すコマンドも利用しません。ファイルやディレ
クトリ、プロセスを修正するコマンドでも利用しません。重要な例外が 1 つあ
ります。引数リストを system もしくは exec に渡す場合、リスト要素には汚
染度チェックが働きません。したがって、汚染モードでの system や exec に
は特に注意を払ってください。

汚染されたデータから派生したデータ値はどれも汚れています。例外が 1 つあ
ります。データをきれいするには、汚染されたデータの部分文字列を抜き出し
ます。ただ、部分文字列としてむやみに「.*」を使わないようにしてください
。汚染を防ぐ仕組みを台無しにしてしまいます。そのかわりに、プログラムが
許容する「安全な」パタンを識別するパタンを使って、「有効な」値を取り出
して下さい。値を取り出した後も、その値をチェックする必要があります(特に
長さ)。

open や glob、backtick 関数はシェルを呼んで、ファイル名に含まれるワイル
ドカード文字を展開します。これがセキュリティホールを開けるのによく使わ
れます。これらの関数をまったく止めるようにするか、perlsec(1)にあるよう
に、より特権を少なくした「サンドボックス」を使用するようにしてください
。特に backtick については、system()を呼び出すように書き直してください
(もしくは完全に書き直して、より安全なものに変更してください)。

率直に言えば、Perl の open()関数は、安全が求められるプログラムにとって
は「何でそうなるのかな？」状態です。open()はテキストを解釈しますが、念
入りにフィルタをかけないと、セキュリティ上の問題がたくさん起こってしま
います。ファイルをオープンしたり、ロックしたりするコードを書く前に、
perlopentut(1) を調べてください。たいていの場合、sysopen()はファイルを
オープンするに当たって、さらに安全な方法 (さらに複雑ですが)を提供してい
ます。新しい Perl 5.6 では、open() の呼び出しにさらに 3 つのパラメタを
用意して、 sysopen()の複雑さを排し、解りにくい動作を無効にしました。
<http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2000-03/
msg02596.html>

Perl プログラムは警告フラグ(-w)を有効にすべきです。これで潜在的に危険で
あったり、古臭い式に警告を出せます。

Perl プログラムは、制限をかけた環境でも動かせます。さらに詳しい情報は、
Perl の標準配布物に入っている「Safe」モジュールを見てください。このモジ
ュールがどの程度監査してくれるか定かではありませんので、これにセキュリ
ティ上の信頼を寄せるのは注意してください。「Penguin Model for Secure
Distributed Internet Scripting」を詳しく調べてもよいでしょう。このドキ
ュメントを書いている時点では、まだコードもドキュメントも利用できないよ
うですが。【訳註：Penguin Model for Secure Distributed Internet
Scripting は http://www.hpcf.upr.edu/~humberto/documents/
penguin-safe-scripting.html を参照してください】

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

9.3. Python

他の言語と同じく、データがプログラムの一部として実行できる関数には、注
意が必要です。信頼できないユーザが、入力に影響を絶対与えないようにして
ください。 exec() や eval()、execfile()がこれに該当します(率直に言って
、compile()を呼び出すものすべてに対して、注意深くチェックすべきです)。
意外なことに、input()式は危険です[Watters 1996, 150]。 

Python プログラム(setuid や setgid したプログラム)で、特権を持たないユ
ーザが実行した、特権がついているプログラムには、「ユーザ」モジュールを
インポートしてはいけません。ユーザモジュールのせいで、pythonrc.py が読
まれたり、実行されたりします。このファイルを信頼できないユーザがコント
ロールすると、攻撃者がユーザモジュールを利用して、信頼できるプログラム
に対して、強制的に勝手なコードを実行させられます。 

Python は、ほとんどコンパイル時にチェックを行いません。基本的にコンパイ
ル時に型情報は存在しません。関数やメソッドに渡るパラメタの数が適正であ
るかのチェックすらありません。これが、潜在的バグをたくさん抱える、とい
う残念な結果を生みます(John Viega 氏と私は、この問題に遭遇しました)。う
まくいけば、いつの日か、Python はオプションとして静的な型付けと型チェッ
クを選択できるようになるでしょう。この点についてはかねてから議論されて
きました。現状は不完全ながら PyChecker という解決策があります。
PyChecker は lint ライクなプログラムで、Python のソースコードによくでる
バグをチェックします。 PyChecker は http://pychecker.sourceforge.net で
取得できます。

Python では RExec クラスで「実行に制限をかける」機能がサポートされてい
ます。この機能の主目的は、アプレットやモバイル・コードの実行にあります
。しかし、外部からコードが渡らなくても、プログラムの特権に制限を設ける
場合にも利用できます。実行に制限をかける環境では、ファイルの読み込みは
、デフォルトで許可しています (書き込みは許可していません)。ネットワーク
へアクセスする操作や GUI によるやりとりはできません。デフォルトは変更可
能ですが、制限をかけた環境で、抜け穴(loophole)ができないように注意して
ください。特にユーザに対して、自由にクラスへ属性を追加できるようにする
と、幾通りもの方法で環境を破壊できます。というのは、Python は「見えない
」メソッドを多量に呼び出して実行しているからです。デフォルトでは、
Python のオブジェクトはほとんど参照渡しです。制限をかけたプログラム環境
にあっても、mutable(変更可能)な値に対する参照を入れ込むと、制限をかけた
プログラムでも、ある程度オブジェクトが変更できます。つまり制限をかけた
環境の外から見えてしまいます。つまり mutable な値にアクセスしたいなら、
mutable な値をコピーするか、 Bastion モジュール(別オブジェクトへの制限
をサポート)を使用してください。詳しい情報は、Kuchling [2000]を見てくだ
さい。制限をかけた環境を実現する機能が、どの程度監査を施すのかは定かで
はありませんので、プログラマの皆さんは注意してください。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

9.4. シェルスクリプト言語(sh と csh 系)

setuid もしくは setgid した安全が求められるコードには、標準的なコマンド
シェルのスクリプト言語(csh や sh、bash のような)を採用しないよう、強く
推奨します。システムには(Linux のような)、setuid や setgid したシェルス
クリプトを完全に無効にしているものもあり、setuid や setgid したシェルス
クリプトを作成すると、移植性の問題がさらに発生します。古いシステムでは
、そもそもシェルスクリプト言語は安全ではありません。それは競合状態を起
こすからです(Section 3.1.3 で論じたように)。その他のシステムにとっても
、あまり良いとはいえません。

実際のケースでは、シェルスクリプト言語を安全が要求されるプログラムに使
うべきではない場合がよくあります。標準的なコマンドシェルは、あいまいな
入力に左右されてしまうのは周知の事実です。普通コマンドシェルは、対話的
に利用してるユーザに対して、「自動的に」動作するように設計してあります
。したがって、クラックする決意を持った人間には対抗できません。シェルプ
ログラムは、安全にする必要が求められないプログラムにとっては、素晴らし
いプログラムです(たとえば、特権を持たないユーザと同じ権限で実行できます
し、「信頼できない」データも受けつけません)。また、入力すべて(たとえば
、ファイルやディレクトリ、コマンドライン、環境変数他)が、信頼できるユー
ザからのものである限り、特権を持って動作するのには好都合です。起動時や
終了時のスクリプトに非常に良く採用されているのはこのためです。

悪意ある入力が存在する状況で、安全なシェルプログラムを作成するのは、他
の言語に比べて困難です。理由は、シェルはすべてから影響を受けるからです
。たとえば、「見えない」環境変数(たとえば、ENV や BASH_ENV、IFS の値)は
、操作方法に影響しますし、スクリプトが実行される前に、ユーザが定義した
任意のコードを実行することさえ可能です。実行ファイル名やディレクトリの
中身のようなものでさえ、実行に影響します。攻撃者が制御文字(たとえば改
行)や空白、シェルのメタキャラクタ、ダッシュ (オプションを示すフラグ)で
はじまるファイル名を作れると、それがつけ込む隙を与えることになります。
たとえば、Bourne シェルの実装の多くは、下記のコードを実行すると、root
でのアクセスを認めてしまいます(この脆弱性を提示してくれた NCSA に感謝し
ます)。

 % ln -s /usr/bin/setuid-shell /tmp/-x                                 
 % cd /tmp                                                             
 % -x                                                                  

システムによってはこの穴を塞いでいるものもありますが、問題が解決した訳
ではありません。コマンドシェルの大部分が、安全に setuid や setgid した
プログラムを書くようにはできていないからです。プログラムの目的として、
setuid したシェルスクリプトの作成は避けてください。システムが setuid し
たシェルスクリプトを許していてもです。そのかわりに、別の言語で小さなプ
ログラムを作成して、環境をクリアにしてから、他の実行形式(シェルスクリプ
トであるかもしれません)を呼ぶようにしましょう。

それでもシェルスクリプト言語の利用にこだわるなら、少なくとも移動もしく
は変更できないディレクトリにスクリプトを置いてください。 PATH と IFS に
は、スクリプトの最初の方で既知の値を設定してください。実際、環境はスク
リプトが呼ばれる以前に整えておくべきです。また最初の方で「cd」して、安
全なディレクトリに移動しておいてください。データを使うなら /etc のよう
な、信頼できるユーザが制御しているディレクトリからのデータにしてくださ
い。攻撃者は、そのようなディレクトリに、悪意を持って名付けたファイルは
入れられませんので。ファイル名はすべて必ず引用符で囲んでコマンドライン
に渡してください。たとえば、$1 ではなく "$1" のように。理由は、空白が入
ったファイル名が分割されてしまうからです。「--」を使ってコマンドを呼び
出し、オプションがさらに追加できないようにしてください。攻撃者がダッシ
ュではじまるファイル名を作成したり、渡してきたりして、プログラムをひっ
かけてオプションであるかのごとく処理させようとするかもしれないからです
。入力ファイル名を注意深く調べ、許可するファイル名には制限をきつくかけ
てください。

同じ意味合いで、安全なポリシを実装している「制限付きのシェル(restricted
shell)」を信頼するのは、お薦めできません。制限付きのシェルは、あえてユ
ーザにさまざまな処理を実行できないようにするシェルです。目的は、ユーザ
にごく限られたプログラムだけを動作させることです。制限付きシェルは、念
には念を入れる手段としては有効ですが、正確に設定できないのは有名で、設
定してもよく破られてしまいます。たとえば制限付きシェルには、ファイル(た
とえば、「.profile」)に制限をかけない状態で実行してから、動作するものが
あります。ユーザがこのファイルを変更できれば、そのコードを実行させてし
まいます。制限付きシェルは、限られた少数のプログラムだけを実行するよう
に設定するべきです。しかし、それらのプログラムのどれかが「シェルエスケ
ープ」を使って、ユーザがさらにプログラムを動かせるようになっていれば、
攻撃者はそのシェルエスケープを利用して制限付きシェルを回避してしまいま
す。もちろん、制限付きシェルの PATH を設定していなければ(どんなプログラ
ムの動作も許可)、攻撃者はプログラムの多くでシェルエスケープを利用できま
す(テキストエディタやメールリーダー等)。問題は、シェルの目的がそもそも
他のプログラムの実行にある点です。他のプログラムが、望んでいない操作を
認めているかもしれません。シェルは、これらの操作の防止には介入しません
。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

9.5. Ada

Ada95 では、Unbounded_String 型の方が、String 型よりも柔軟であるケース
が多いです。理由は、必要に応じて自動的にサイズが変わるためです。しかし
、パスワードや秘密鍵のような機密の値を Unbounded_String には入れないで
ください。コアダンプやページエリアにそれらの値が後々まで残ってしまって
いるかもしれないからです。そういう場合には、String 型を使って、others
=> ' ' のように、定数ですぐに上書きしてください。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

9.6. Java

Java を使って安全なプログラムを開発しているなら、まず最初のステップ
(Java の学習後)は、Java のセキュリティについての 2 つの基礎的なテキスト
を読むことです。そのテキストは、Gong [1999]と McGraw [1999](後者につい
ては、特にセクション 7.1 を見てください)。また、Sun が投稿した安全なコ
ードのためのガイドライン http://java.sun.com/security/seccodeguide.html
も見てください。 Java のセキュリティモデルについてのスライドが、 http:/
/www.dwheeler.com/javasec で自由に見られます。 McGraw [1998]もあわせて
見てください。

皆さんが開発しているようなアプリケーションは、明らかにたくさんのものに
依存しています。クライアント側での利用を目的にした Java のコードは、サ
ーバ側のコード以上にまったく異なった環境(と信頼モデル)にあります。もち
ろん一般原則は適用できます。たとえば、信頼できないユーザからの入力に対
しては、その入力をチェックしてフィルタをかけなければいけません。しかし
、Java では「隠れた」入力や、下記で論じるような配慮すべき潜在的な入力が
存在します。 Johnathan Nightingale [2000] には、Java プログラミングにお
ける課題を要約した記述が興味深く、いろいろと書いてあります。

   
    … Java プログラミングで大事なのは、継承に気をつけることです。親か
    らのメソッドやインタフェース、親のインタフェースを継承するなら、コ
    ードに穴が開く危険があります。
   
キーとなるガイドラインを Gong [1999]や McGraw [1999]、Sun のガイダンス
、そして私自身の経験からいくらか書いてみます。

 1. public なフィールドもしくは変数は、使わないでください。private で宣
    言して、それらへのアクセス機能を提供し、制限をかけてから利用してく
    ださい。
   
 2. メソッドは他に理由がない限り、private にしてください(もし private
    にしないなら、ドキュメントに理由を記載してください)。 private でな
    いメソッドは、自分自身で防御しなければいけません。なぜなら、汚染さ
    れたデータを受け取るかもしれないからです(どうにかして防御する手はず
    を整えない限りは)。
   
 3. JVM(Java Virtual Machine)は、アクセシビリティ修飾子(たとえば、「
    private」) をアプリケーション(アプレットとは対照的に)実行時に実際に
    は実施しない可能性があります。この点を「Secure Programming」メーリ
    ングリストで 2000 年 11 月 7 日に指摘してくれた John Steven 氏
    (Cigital Inc.)に感謝します。この問題は、どのクラスのローダーが、ア
    クセスを要求するクラスをロードするかに左右される点にあります。クラ
    スが信頼できるクラスのローダー(null もしくは基底クラスのローダーを
    含む) からロードされれば、アクセスチェックは「真」を返します(アクセ
    スを許可)。たとえば、下記のように動作します。 (少なくとも、Sun の
    1.2.2 VM では。他の実装では動作しないかもしれません)。
   
     a. public フィールドを持つ犠牲者クラス(V)を書き、コンパイルします
        。
       
     b. 先程のフィールドにアクセスする「攻撃者」クラス(A)を書き、コンパ
        イルします。
       
     c. V の public フィールドを private に変更して、再コンパイルします
        。
       
     d. A を動かします。A は V の(現在は private な)フィールドにアクセ
        スします。
       
    しかし、アプレットでは状況が変わります。 A をアプレットに変換し、ア
    プレットとして動作させると(たとえば、アプレット・ビューアーやブラウ
    ザで)、クラスローダーは、もはや信頼された(もしくは null) クラスのロ
    ーダーになっています。つまり、コードは、
    java.lang.IllegalAccessError に投げられ、クラス A から V.secret フ
    ィールドにアクセスしようとしている、というメッセージを出します。
   
 4. static フィールドの変数は使わないでください。そのような変数はクラス
    に属します(クラス・インスタンスではなく)。そして、クラスは他のクラ
    スによって位置づけられて、static フィールドの変数は他のどのクラスか
    らも見られるようになります。こうなってしまうと、安全にするのがます
    ます難しくなります。
   
 5. コードに悪意があるかもしれない場合、mutable オブジェクトを決して返
    さないようにしてください(コードが mutable オブジェクトを変更してし
    まうかもしれないため)。配列は mutable であることに注意してください
    (配列の中身が mutable でなくてもです)。したがって、機密データが入っ
    た内部配列への参照は返さないでください。
   
 6. ユーザの既知の mutable なオブジェクト(オブジェクトの配列を含む)を決
    してそのまま保存しないでください。さもないと、ユーザがオブジェクト
    を安全が必要となるコードに渡してしまうかもしれません。安全が必要な
    コードは、そのオブジェクトを「チェック」し、そのデータを使いながら
    、変更してください。配列は内部で保存する前にコピーして、注意深く扱
    ってください(たとえば、ユーザが作成したコピー・ルーチンには注意して
    ください)。
   
 7. 初期化に頼らないでください。初期化していないオブジェクトを割り当て
    る方法は、いくつかあります。
   
 8. 特に理由がなければ、すべてを final としてください。クラスもしくはメ
    ソッドが final でないと、攻撃者が危険かつ思いがけない方法で拡張しよ
    うとするかもしれません。こうすると、セキュリティと引き換えに拡張性
    が犠牲になることを忘れないでください。
   
 9. セキュリティは、パッケージのスコープに頼らないようにしてください。
    デフォルトで閉じている java.lang のようなクラスは少数です。Java
    Virtual Machine(JVM)には、他のパッケージを閉じさせようとするものも
    あります。そうでなければ、Java のクラスは閉じていません。つまり、攻
    撃者は新しいクラスをパッケージ内部に導入することで、この新しいクラ
    スを使って、防御していると思っているオブジェクトにアクセスできてし
    まいます。
   
10. inner クラスを使用しないでください。 inner クラスがバイトコードに変
    換されると、inner クラスはパッケージの中のあらゆるクラスからアクセ
    スできるクラスへと変換されてしまいます。さらに悪いことに、クラスの
    プライベートなフィールドを取り囲むと暗黙に private ではなくなり、な
    んと inner クラスからのアクセスを認めてしまいます。
   
11. 特権を最低限にしてください。できるだけ、特別なパーミッションをまっ
    たく必要としないようにしてください。 McGraw 氏は、さらに踏み込んで
    、どんなコードにも署名しないように推奨しています。私はあえてコード
    に署名しています(そうすると、ユーザが「(ある特定の )送り手の一覧に
    ある人が署名したコードだけを実行可能」という選択ができます)。しかし
    、特権を設定するサンドボックスそのものを必要とするよう、プログラム
    を書いてください。さらに特権を持つ必要があるなら、とりわけ厳しくそ
    のコードを監査してください。
   
12. コードに署名しなければいけないなら、1 つのアーカイブファイルにすべ
    てを納めてください。 McGraw [1999]から引用するのが適切ですので、下
    記に載せます。
   
       
        この規定の目的は、異なる手段を組み合わせた攻撃を防ぐことにあり
        ます。この攻撃は、攻撃者が悪意あるコードと署名済みのクラスを一
        緒にリンクしたり、意図的に絶対一緒に使うことがないように作られ
        た署名済みクラスとリンクしたりして、新しいアプレットやライブラ
        リを構築しようとします。クラスのグループにもあわせて署名すると
        、この攻撃がさらに困難になります。コードに署名を行う既存のシス
        テムでは、十分に異質なものを組み合わせた攻撃に対処できません。
        したがってこの規定は、そのような攻撃を完全には防ぎ切れません。
        しかし、アーカイブを 1 つにしておけば、打撃は受けません。
       
13. クラスが複製できないようにしてください。 Java がオブジェクトを複製
    する仕組みは、コンストラクタが何も動かなくても、攻撃者がクラスのイ
    ンスタンスを作成できてしまいます。クラスを複製できないようにするた
    めに、クラスそれぞれで下記のメソッドを定義してください。
   
    public final void clone() throws java.lang.CloneNotSupportedException { 
       throw new java.lang.CloneNotSupportedException();                    
       }                                                                    
   
    どうしてもクラスを複製可能にする必要があるなら、攻撃者が複製したメ
    ソッドを再定義できないようにする方法がいくつかあります。自分で複製
    したメソッドを定義しているなら、final にしてください。定義していな
    いなら、少なくとも下記を追加して、悪意あるオーバーライドを防げます
    。
   
    public final void clone() throws java.lang.CloneNotSupportedException { 
      super.clone();                                                        
      }                                                                     
   
14. クラスはシリアライズできないようにしてください。シリアライズすると
    、攻撃者が private な部分であっても、オブジェクトの内部状態を見られ
    るようになります。これを防ぐには、このメソッドをクラスに追加してく
    ださい。
   
    private final void writeObject(ObjectOutputStream out)             
      throws java.io.IOException {                                     
         throw new java.io.IOException("Object cannot be serialized"); 
      }                                                                
   
    シリアライズが可能な場合、フィールドがシステムのリソースを直接扱っ
    ていたり、アドレス空間に関連する情報を含んでいたりするなら、そのフ
    ィールドに transient を設定するようにしてください。そうしないと、ク
    ラスをデシリアライズすると不適切なアクセスを認めることになるかもし
    れません。機密の情報は transient であると見なしても良いと思います。
   
    自分でクラスにシリアライズするメソッドを定義するなら、どんな
    DataInput や DataOutput メソッドにも内部配列を渡すべきではありませ
    ん。根本的な理由は、DataInput や DataOutput メソッドが、オーバーラ
    イド可能だからです。シリアライズできるクラスが private な配列を直接
    DataOutput(write(byte [] b)) メソッドに渡したとすると、攻撃者が
    ObjectOutputStream をサブクラス化して write(byte [] b)メソッドをオ
    ーバーライドし、private な配列にアクセスしたり、修正したりできるよ
    うにしてしまいます。デフォルトのシリアライズは、private なバイト配
    列フィールドを DataInput や DataOutput のバイト配列メソッドに公開し
    ません。
   
15. クラスをデシリアライズしないでください。クラスをシリアライズしてい
    なくても、デシリアライズできるかもしれません。攻撃者が好みの値を入
    れたバイトシーケンスを作って、クラスのインスタンスとしてデシリアラ
    イズできます。見方を変えると、デシリアライズは一種の public なコン
    ストラクタで、攻撃者がオブジェクトの状態を選択できるようにします。
    この操作は明らかに危険です。これを防ぐには、下記のメソッドをクラス
    に追加してください。
   
    private final void readObject(ObjectInputStream in)                
      throws java.io.IOException {                                     
        throw new java.io.IOException("Class cannot be deserialized"); 
      }                                                                
   
16. 名前でクラスを比較しないでください。攻撃者は、どのみち同じ名前でク
    ラスを定義できます。注意しないと、これらのクラスに望ましくない特権
    を与えてしまい、混乱が生じます。ここでは、間違った例として、オブジ
    ェクトが既知のクラスかどうかを判断する例を載せておきます。
   
      if (obj.getClass().getName().equals("Foo")) {             
   
    2 つのオブジェクトが、間違いなく同じクラスであると判断する必要があ
    れば、 getClass()を両者にかけてから、== 演算子で比較してください。
    つまりこのようになります。
   
      if (a.getClass() == b.getClass()) {                       
   
    オブジェクトが既知のクラス名を本当に持っているかどうかを決める必要
    があるなら、杓子定規に、必ず現在の名前空間(今使っているクラスのクラ
    スローダー)で使うようにしてください。下記のような形式を使ってくださ
    い。
   
      if (obj.getClass() == this.getClassLoader().loadClass("Foo")) {
   
    このガイドラインは McGraw 氏と Felten 氏のドキュメントからの引用で
    す。このガイドラインは優れています。私はこれに加筆して、クラスの値
    による比較はできるだけ避けるのが得策であるとしました。今必要性がま
    ったくないとしても、クラスメソッドやインタフェースを設計する方が適
    切です。しかしいつも設計するのは無理なので、これらのテクニックを知
    っていると役に立ちます。
   
17. 機密情報(暗号鍵やパスワード、アルゴリズム)をコードやデータに保存し
    ないでください。 JVM には簡単にこのデータを見せてしまう好ましくない
    ものがあります。コードを複雑にしても、実力がある攻撃者にはコードを
    隠しておけません。
   
 

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

9.7. TCL

TCLは、「tool command language」の略語で、「ティクル」と呼びます。 TCL
は、言語とライブラリの 2 つの部分から構成されています。言語はシンプルな
テキスト言語です。コマンドを呼び出して、対話的なプログラムを動かすのに
向いており、基本的なプログラミング機能も備えています。ライブラリは、ア
プリケーションプログラム内に組み込まれます。

TCL についての情報はさらに、 TCL WWW Info <http://www.sco.com/
Technology/tcl/Tcl.html> のようなサイトのページで見られます。非常に興味
深いのは、Safe-TCL(TCL でサンドボックスを作る)や Safe-TK (Safe-TCL 用に
サンドボックス化した移植性のある GUI)です。同じく WebWiseTclTk Toolkit
は TCL パッケージを自動的に配置して WWW のどこからでもロードをできるよ
うにしています。 WebWiseTclTk Toolkit については、 http://
www.cbl.ncsu.edu/software/WebWiseTclTk. にさらに詳しい情報があります。
どの程度コードをレビューしてあるのか、はっきりしません。さらに役立つ情
報が、comp.lang.tcl の FAQ http://www.tclfaq.wservice.com/tcl-faq に載
せてあります。しかし TCL が目指しているところが、小さく、「シンプル」な
言語であるゆえに、思った以上に制限があります。 Richard Stallman 氏の「
Why You Should Not Use TCL」 <http://sdg.lcs.mit.edu/~jchapin/6853-FT97
/Papers/stallman-tcl.html> を見てください。たとえば、TCL は概念上、デー
タ型は 1 つしか存在せず(文字列)、これがさまざまなプログラムの作成を難し
くしています(実行も遅くなっています)。また、私が TCL プログラムを書いた
時にわかったことがあります。それは、悪意ある入力文字列によって、簡単に
プログラムが厄介で思いがけない動作をしてしまう点です。たとえば、攻撃者
はあなたの TCL プログラムを利用して、予期しなかったことを実行してしまう
かもしれません。予期しなかったこととは、TCL にとって特別な意味を持つ文
字であるスペースや二重引用符、中括弧、ドル記号、ブラケットを送りつける
ことです(もしくは、処理中にこれらの文字を発生させる入力を作成します)。
つまり、セキュリティの境界に位置して、仲介をしなければならないプログラ
ムを書くのには、TCL を推奨できません。どうしても TCL を選びたいなら、細
心の注意を払って、ユーザの入力によってプログラムが「だまされない」よう
にしてください。その一方で、TCL プログラムがモバイル用コードを実装する
のに全然利用できない、という理由(不十分なレビュー以外に)を理解できませ
ん。私が推奨する以上に TCL の利用を支持している人たちがいます。それは
TCL がサンドボックスを出来合いで実装している数少ない言語の 1 つだからで
す。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

9.8. PHP

SecureReality は、非常に興味をそそる「A Study In Scarlet - Exploiting
Common Vulnerabilities in PHP」[Clowes 2001]」というドキュメントを出し
ていて、PHP 4.1.0 以前のバージョンにターゲットを当て、安全なプログラム
を書く上で問題となる点のいくつかを論じています。このドキュメントでは「
努力したとしても、PHP で安全なアプリケーションを書くのは非常に難しい
(PHP のデフォルトの設定では)」と結論づけています。

どんな言語にもセキュリティ上の問題はありますが、PHP には安全上おそらく
他の大半の言語と比べて際だった問題点が 1 つあります。それは名前空間にデ
ータをロードする方法です。デフォルトで PHP (バージョン 4.1.0 もしくはそ
れよりも古いバージョン)は、 Web 上の PHP へと送られる環境変数とその値を
すべて、自動的に同じ名前空間 (グローバル変数)にロードします。通常の変数
もそこにロードします。したがって、攻撃者は自由に変数やその値を設定可能
で、PHP プログラムがあえて再設定しない限り、その値はそのままになってい
ます。さらに PHP は最初に変数を作る要求があった時に、デフォルトの値を設
定します。したがって、PHP プログラムは変数を初期化しないのが普通です。
変数を設定するのを忘れると、PHP は報告をあげますが、デフォルトではそう
なっていません。ただ忘れてはいけない点は、これが単にエラーの報告であっ
て、攻撃者が普通でない方法を見つけて、エラーを起こすことを止められない
ことです。つまり PHP はデフォルトでは、プログラムが攻撃者に対して特別に
注意を払って攻撃者を負かさない限り、プログラムにある変数すべての値のコ
ントロールを完全に許してしまっています。プログラムが動きだすと、これら
の変数を再設定できますが、どの変数の再設定に失敗しても(はっきりとしてい
なくても) PHP プログラムの脆弱さがあらわになるでしょう。

たとえば、下記の PHP プログラム(Clowes 氏による例)は、パスワードを知っ
ている人にだけ何か重要な情報を与えようとしていますが、攻撃者は Web ブラ
ウザで「auth」に値を設定し、認証チェックの効力を失わせられます。

 <?php                                                                 
  if ($pass == "hello")                                                
   $auth = 1;                                                          
  ...                                                                  
  if ($auth == 1)                                                      
   echo "some important information";                                  
 ?>                                                                    

私の他にも、このとりわけ危険な問題を批判する人が大勢います。PHP は広範
に使われているので、問題は深刻です。結局、簡単に使える言語は、簡単に安
全なプログラムを書けるようになっています。 PHP では、設計時に見通しを誤
ってしまったこの機能を無効にできます。「register_globals」を「off」にす
ればよいのです。しかし、PHP の 4.1.0 より新しいバージョンでは、デフォル
トで「on」になります。4.1.0 以前は register_globals を off にして使用す
るのは困難です。 PHP の開発者は、PHP 4.1.0 のアナウンスの中で下記のよう
に述べています。「PHP の次の準メジャー・バージョンアップでは、デフォル
トで register_globals は off になってインストールされます」

「register_globals」が「on」になっている PHP は、重要なプログラムにとっ
て危険な選択となります。いとも簡単に安全でないプログラムが書けるからで
す。しかし、「register_globals」が「off」になりさえすれば、PHP は開発す
るのになかなか使える言語になります。

デフォルトを安全にするには、「register_globals」を「off」にすること、ユ
ーザが外部の情報源から得る入力に対して設定を行い、制限をかけやすくでき
る機能を追加することが挙げられます。 Web サーバ(Apache のような)は、独
自に PHP を安全に設定してインストールできます。ユーザが受け取りたい入力
変数が簡単にリストアップできるようなルーチンを PHP ライブラリに入れられ
ます。関数には、変数が持たなければならないパタンおよび変数が強制されな
ければならない型をチェックするものがあります。私の考えでは、現状、安全
な Web 開発に PHP を採用するのはどうかと思います (register_globals が
on なので)。しかし、ちょっとした修正をすれば、手ごろな手段になります。

PHP を使おうと決めたなら、ここでアドバイスをいくつか書いておきます(これ
らのアドバイスの多くは、Clowes 氏が提起している問題への対処方法をベース
にしています)。

 ・ PHP の設定オプションである「register_globals」を「off」にして、
    4.1.0 以上のバージョンを利用してください。 PHP 4.1.0 ではいくつか特
    別な配列を用意していて、その中でも $_REQUEST は「register_globals」
    を「off」にしている場合に PHP でのソフトウェア開発を容易にします。
    register_globals を設定することで、PHP に対する一番よくある攻撃を完
    全に排除できます。またこの設定が新規インストールのデフォルトになる
    時の準備にもなります。 register_globals が off であることを前提にす
    るなら、まずこの点をチェックする必要があります(そうなっていなければ
    中断します)。そうすれば、プログラムをインストールする人が、問題があ
    ることにすぐ気付きます。サードパーティの PHP アプリケーションでこの
    設定で動作するものは少数です。したがって現状では、Web サイトで完全
    に off にするのは困難であることを忘れないでください。また、「
    register_globals」を無効にすると、サードパーティによるホスティング
    も難しくなります。プログラムのいくつかだけが「register_globals」を
    「off」にしていることは可能です。たとえば Apache なら、下記の行を
    PHP のディレクトリの .htaccess ファイルに加えてください(もしくは
    Directory 命令を使ってさらに制御をかけてください)。
   
     php_flag register_globals Off                              
     php_flag track_vars On                                     
   
    しかし .htaccess ファイル自体、Apache の Web サーバが設定の上書きを
    許可していなければ、無効になります。Apache 全体の設定は
    AllowOverride が None と設定されているのが普通です。したがって
    Apache ユーザならば、Web のホスティング・サービスに対して、「
    AllowOverride オプション」を設定ファイルに設定するように説得してみ
    てください。そうできたなら、ヘルパー関数を書いて、必要なデータ(その
    データだけ)をそのままロードしてください。
   
 ・ register_globals が on になって動いていると思われるところで、ソフト
    ウェアを開発しなければならないなら(たとえば、あちこちに存在する PHP
    アプリケーション)、ユーザが設定していない値を常に設定するようにして
    ください。 PHP のデフォルト値を前提にしないでください。また自分で確
    かに設定した変数でなければ、信用してはいけません。入口になるどの部
    分でも、これを行わなければいけません (たとえば PHP プログラムと PHP
    を使った HTML ファイルすべて)。最善の解決策は、PHP プログラムそれぞ
    れに対して、使用する変数すべてに値を設定することです。ただそれらに
    普通のデフォルト値("" や 0)を再設定するとしてもです。これには、実行
    に必要な include されるファイルに入っているグローバル変数やライブラ
    リすべてにも当てはまります。あいにくこの点が、提案を実行することを
    困難にしています。それは、開発者の中ですべてのグローバル変数がすべ
    ての関数から利用されるかもしれないという点を本当に知っていて、理解
    している人が少ないからです。それより劣る方法ですが、HTTP_GET_VARS
    や HTTP_POST_VARS、HTTP_COOKIE_VARS、 HTTP_POST_FILES を捜し出し、
    ユーザがデータを用意しているが、プログラマがその情報すべてをチェッ
    クし忘れていないかを見つけます。また PHP が新しいデータ源を追加する
    と何が起こるかも見つけます(たとえば、HTTP_POST_FILES は古いバージョ
    ンにはありません)。
   
 ・ エラー報告のレベルを E_ALL に設定して、すべてのエラーがテスト中に報
    告されるようにしてください。何よりこの報告には、初期化していない変
    数についての警告があります。これが PHP では重要な問題になります。と
    にかく PHP を使いはじめるなら、これは良い考えです。なぜならプログラ
    ムをデバッグするのにも役立つからです。エラー報告のレベルを設定する
    のには、いろいろな方法があります。「php.ini」ファイル(全体)や
    「.htttpd.conf」ファイル(ホスト 1 台)、「.htaccess」ファイル(複数ホ
    スト)、もしくはスクリプトのトップレベルで、エラー報告関数を通して行
    なう等があります。推奨するエラー報告レベルの設定方法は、php.ini フ
    ァイルとトップレベルのスクリプト両方で設定する方法です。そうすれば
    、(1)トップレベルのスクリプトにコマンドを入れ忘れる(2)プログラムが
    別のマシンに移動して php.ini ファイルを変更し忘れる、ということが防
    げます。つまり PHP プログラムそれぞれが、下記のようにはじまるべきで
    す。
   
      <?php error_reporting(E_ALL);?>                           
   
    エラーの報告は、開発中に有効にし、本番のサイトでは無効にすべきであ
    る、という点については議論の余地があります(そのようなエラー・メッセ
    ージは攻撃者にとって役に立つ情報を提供する可能性があるからです)。問
    題なのは、「実運用する」時に無効にし、そのままの状態で開発中も無効
    にしておくことです。したがって、当面は単純なアプローチを取って、開
    発、本番それぞれのはじまりに入れることを推奨します。
   
 ・ ファイル名を作成するのに使われるユーザ情報は、どれも注意深くフィル
    タしてください。とりわけリモートファイルへのアクセスは防いでくださ
    い。 PHP はデフォルトで「リモートファイル」機能がついてきます。つま
    り、fopen() のようなファイルをオープンするコマンドが存在しています
    。他の言語がローカルファイルだけをオープンできるのに対して、他のサ
    イトからの Web や ftp の要求を呼び出すのに実際よく使われます。
   
 ・ PHP の古い形式でファイルのアップロードをしないでください。
    HTTP_POST_FILES 配列とそれに付随した関数を使ってください。 PHP はフ
    ァイルをアップロードするのに、そのファイルをどこかのテンポラリのデ
    ィレクトリに特定の名前で置いています。 PHP はそもそも、変数の寄せ集
    めに対して設定を行い、ファイル名がどこにあるかを示します。しかし、
    攻撃者は変数名やその値をコントロールするのが可能なので、その機能を
    使って、とんでもないことを起こせます。そのかわりに、HTTP_POST_FILES
    とそれに付随した関数を使って、アップロードされたファイルにアクセス
    してください。この解決方法を取ったとしても、攻撃者が勝手な内容のフ
    ァイルをテンポラリでアップロードできてしまいます。これはそれ自体危
    険です。
   
 ・ ドキュメントツリーには、保護済みの入口部分だけを入れてください。他
    のコード (大部分がそうであるべきですが)は、ドキュメントツリーの外に
    置いてください。 PHP はこのトピックスについて、残念な報告が過去いろ
    いろありました。元々は、PHP ユーザは「.inc」(include)拡張子を使って
    、「含まれる」ファイルをサポートしてきました。しかし、このファイル
    にはパスワード他の情報も入ります。また Apache は「.inc」ファイルが
    ドキュメントツリーにあり、要求がありさえすれば、要求者にその内容を
    与えてしまっていました。これまで開発者は、すべてのファイルに「.php
    」という拡張子を付けていました。これはこのファイルが見られないこと
    を意味します。しかし、入口部分ではなかったファイルが入口になってし
    まえば、そこが時として悪用されてしまいます。先程述べたように、セキ
    ュリティ上のアドバイスで一番大切な点は、いつも同じです。ドキュメン
    トツリーには、保護済みの入口部分(ファイル)だけを入れてください。他
    のコード(たとえば、ライブラリ)は、ドキュメントツリーの外に置いてく
    ださい。どんな「.inc」ファイルもドキュメントツリーには入れないでく
    ださい。
   
 ・ セッション機構を避けてください。「セッション」機構は、便利に永続的
    なデータを保存できますが、現状の実装には問題点がたくさんあります。
    まず、デフォルトではセッションはテンポラリファイルに情報を保存しま
    す。したがって、マルチホストなシステムであると、数ある攻撃や情報流
    出に対して隙を見せることになります。今はマルチホストなシステムでは
    なくても、いつかそうなるとも限りません。この情報をファイルシステム
    ではなく、データベースと「紐づける」ことも可能です。しかし、別の人
    間がマルチホストなデータベース上で同じパーミッションでデータベース
    にアクセスできるなら、問題は一緒です。気をつけていないと曖昧になり
    ますし(「セッション値なのか攻撃者が設定した値なのかわからない)、攻
    撃者が選んだ内容のファイルや鍵をサーバに無理やりおいてしまうことも
    可能です。これは物騒な状況です。また、攻撃者はある程度、ファイル名
    や鍵名をどこに置くかをコントロールすることさえ可能です。
   
 ・ 入力がアクセスしてかまわないのか、パタンに照らし合わせてすべてチェ
    ックしてください(言語と同じように)。そして型変換を使って、文字列で
    はないデータを強制的にあるべき型にしてしまってください。「ヘルパー
    」関数を開発すればチェックが簡単になり、(予想範囲内の)入力が選ばれ
    たリストから取り込めます。 PHP は型の制約が緩く、これが問題を起こし
    ます。たとえば、入力データの値が「000」なら、「0」とは等しくなりま
    せんし、empty() も等しくなりません。これは連想配列にとって、とりわ
    け重要です。それはインデックスが文字列だからです。 $data["000"]は
    $data["0"]とは違うことを意味します。たとえば、$bar が double 型であ
    ると確認しなければいけません(確認した後は、 double 型にとってのみ、
    正しいフォーマットとなります)。
   
      $bar = (double) $bar;                                     
   
 ・ 危険をはらんでいる関数には特に注意を払ってください。この関数には
    PHP コードの実行(たとえば、exec()や passthru()、backtick 演算子、
    system()、popen())やファイルのオープン(たとえば、fopen()や readfile
    ()、file())等があります。これは完璧なリストではありません。
   
 ・ 適切な場合には、magic_quotes_gpc()を使ってください。いろいろな攻撃
    を排除します。
   
【訳註：原著では、オブジェクト指向スクリプト言語 Ruby にふれていません
。訳註として簡単に Ruby のことにふれたいと思います。 Ruby にはセキュリ
ティモデルが存在しています。大きくわけて 2 つの危険なケースを想定してい
ます。 1 つは、信頼できないデータを扱う場合、もう 1 つは、信頼できない
プログラムを扱う場合です。このケースに対応して、レベル 0 から 4 までの
セキュリティ・レベルを $SAFE というグローバル変数を用いてスレッド単位に
設定できます。ただし注意していただきたいのは、C で書かれた組み込みライ
ブラリ、拡張ライブラリいずれとも、すべての汚染をチェックしている保証が
ない点です。汚染をチェックするのは、作成者にまかされています。セキュリ
ティモデルの詳細については、「オブジェクト指向スクリプト言語 Ruby リフ
ァレンスマニュアル」の「セキュリティモデル」 <http://www.ruby-lang.org/
ja/man-1.6/?cmd=view;name=
%A5%BB%A5%AD%A5%E5%A5%EA%A5%C6%A5%A3%A5%E2%A5%C7%A5%EB> を参照してくだ
さい】

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

Chapter 10. 専門的な話題

                                    見識ある人にはその見識が命の泉とな 
                                    る。無知な者には無知が諭しとなる。 
                                                                       
                                          旧約聖書箴言 16 章 22 節(NIV)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

10.1. パスワード

できるだけパスワードを扱うコードを自前で書かないようにしてください。特
にローカルなアプリケーションの場合、通常行うユーザのログイン認証にまか
せてしまうようにしてください。アプリケーションが CGI スクリプトの場合、
Web サーバが用意している防御にできるだけまかせてください。ただし Web サ
ーバにおける認証の扱い方については下記を参照してください。アプリケーシ
ョンがネットワーク経由で利用するものなら、平文でパスワードを送らないで
ください(できるだけ)。というのは、ネットワークを盗聴することで、いとも
簡単に横取りされて、後で使われてしまうからです。パスワードを「暗号化」
しても、その暗号化アルゴリズムで固定の鍵を使っていたり、何かしかの非公
開アルゴリズムを使っていたりするなら、本質的に平文でパスワードを送って
いるのと同じです。

ネットワークで利用するなら、少なくともダイジェスト・パスワードの使用を
考えてください。ダイジェスト・パスワードはハッシュで生成するパスワード
です。通常は、サーバがクライアントに何かデータ(たとえば、日付、時間、サ
ーバ名)を送り、クライアントはこのデータとユーザのパスワードを組み合わせ
、この値(「ダイジェスト・パスワード」と呼びます)をハッシュします。そし
てハッシュした結果をそのままサーバに返します。サーバはこのハッシュ値を
検証します。これはうまくいきます。というのは、パスワードはどんな形でも
実際には送られないからです。パスワードはハッシュ値の元として使われるだ
けです。ダイジェスト・パスワードは普通の意味では「暗号」とは見なされま
せんので、法律で機密用の暗号に制限を設けている国でも認められています。
ダイジェスト・パスワードは、直接しかけてくる攻撃には弱いのですが、ネッ
トワークの盗聴に対しては有効です。弱点の 1 つに、ダイジェスト・パスワー
ドの動作があります。サーバはハッシュしていないパスワードをすべて持って
いなければならず、これがサーバを攻撃の対象として魅力あるものにしていま
す。

アプリケーションでユーザがパスワードを設定できるのなら、パスワードをチ
ェックして、「適切な」パスワードだけを許可してください(辞書に載っていな
い、一定以上の文字数である、等)。適切なパスワードの付け方を見つけたいな
ら、 http://consult.cern.ch/writeup/security/security_3.html を見てはど
うでしょうか。 PAM が使えるなら利用しましょう。交換可能なパスワード検証
機能がサポートされるからです。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

10.2. Web の認証

Web の世界では Web サーバは通常ユーザ認証をするのに SSL もしくは TLS を
使い、サーバ側が認証しています。しかしユーザが誰なのかの認証は、簡単な
ことではありません。 SSL や TLS はクライアント側の認証ですが、実際に使
用するに当たって、問題をたくさん抱えています(たとえば、Web ブラウザは共
通のユーザ認証形式をサポートしておらず、ユーザがインストールするのは面
倒です)。 Java や Javascript を使うと、それ自身に問題があります。それは
、ユーザの多くが無効にしていたり、ファイアーウォールにフィルタをかけて
いたりするからです。そして、どちらかというと遅くなります。たいていの場
合、ユーザ毎にプラグインをインストールするのは非現実的でもあります。し
かし、システムが比較的ユーザが少ないイントラネット向けなら、この方法は
適切かもしれません。

イントラネット用のアプリケーションを構築しているなら、通常は認証システ
ムが何であれ、ユーザが利用しているものを使った方がよいでしょう。つまり
、ユーザが Kerberos に依存しているなら、システムは Kerberos を使うよう
に設計してください。認証システムは、アプリケーションの他の部分から独立
させておいてください。組織というものは、そのうち認証システムを変更する
かもしれないからです(変更したがります)。

テクニックには、機能しないか、動作してもうまくいかないものがたくさんあ
ります。「ベーシック認証」という方法を使うとうまくいく場合があります。
この方法はすべてのブラウザやサーバで基本的に備わっています。うまくない
ことに、ベーシック認証はパスワードを暗号化せずに送ります。したがってパ
スワードを盗み取るのは本当に簡単です。ベーシック認証はたいして重要では
ない情報を扱うだけなら、単独で十分役に立ちます。ベーシック認証のパスワ
ードを SSL や TLS 通信(暗号化します)ですべて被せてしまえます。しかしこ
れはパフォーマンスを犠牲にします。「ダイジェスト認証」という手も使えま
す。これは優れた手法ですが、ブラウザが広くサポートしているわけではあり
ません。認証情報をユーザが選んだ URL に入れることもできますが、そうして
はいけない状況がほとんどです。この情報をリークする方法はあまりにたくさ
ん存在します(たとえば、ブラウザの多くが保存している履歴ログやプロクシの
ログ、そして Referer: フィールド経由で他の Web サイトを使って)。

そういう訳で、今日 Web で最も良く使われている認証方法は、クッキーを利用
したものです。クッキーは、認証のために設計されたわけではありません。し
かし認証目的にも使うことができます。しかし使い方を誤れば、セキュリティ
の脆弱さをさらしてしまいます。注意してください。クッキーについて詳しい
情報は、IETF RFC 2965 を以前の仕様書とともに見てください。クッキーを使
う場合に、ブラウザには(たとえば、Microsoft Internet Explorer 6) プライ
バシー・プロファイル(p3p.xml という名前で、サーバのルートディレクリに存
在します)を強要するものもあります。

ユーザにはクッキーを受け取らない人もいて、この解決方法ではまだ問題があ
る点を気に留めておいてください。欲を言えば、この認証情報は HTML フォー
ムの hidden フィールドを経由してやり取りすべきです(大部分のブラウザでサ
ポートしていますので心配無用です)。これまでまったく違った技術を用いて、
データをユーザからサーバに送っていたとしても、クッキーと同じような解決
方法を使ってきていると思います。もちろんこの解決方法を実現するなら、そ
れらのページのキャッシュが、第三者に絶対に使われないようにする設定が必
要になります。クッキーを使わない方が望ましいとは思いますが、その他の解
決方法では実際にはさらに多くの開発負荷がかかります。そのため、多数のア
プリケーション開発者が皆そろって実行するのは困難なので、今はこの解決方
法を強くお薦めはしません。正しく使うのがあまりにも難しい方法(開発者もユ
ーザも)よりも、それなりに安全で、それなりに使いやすい方法について説明し
たいと思います。しかしそれほど苦労なくできるなら、ぜひとも認証情報をフ
ォームの hidden フィールドと暗号化したリンクを使って送ってください(たと
えば、SSL や TLS)。

Fu [2001] では、Web におけるクライアント側の認証について論じています。
これまでに推奨した方法と並んで、ほとんどのサイトでお薦めできる方法です
。これの基本的な考え方は、クライアント側の認証には「ログイン手続き」と
「その後に続く要求」の2 つに分けられるという考え方です。ログイン手続き
では、サーバはユーザにユーザ名とパスワードを求め、ユーザはそれらを提供
し、サーバはそれに対して「認証トークン」で答えます。引き続き起こる要求
で、クライアント(Web ブラウザ)は認証トークンをサーバに (リクエストと同
様に)送ります。サーバはトークンが正当なものか確認し、正当なものなら要求
をかなえます。 Seifried [2001]は、Web での認証について Fu [2001]に匹敵
する情報です。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

10.2.1. Web の認証――ログイン

ログイン手続きは通常 HTML のフォームを使って実装しています。そのフィー
ルド名には、「username」や「password」が適切です。そうしておけば、Web
ブラウザは自動的にうまい具合に動作をしてくれます。パスワードは、必ず暗
号化された通信で送られるようにしてください(https を使った SSL や TLS を
利用した通信)。さもないと盗聴する人がパスワードを収集できてしまいます。
パスワードを入力するテキストフィールドはすべて、パスワードを扱うものと
して作成してください。そうすればパスワードのテキストはユーザ画面が見ら
れる人誰もが読めなくなります。

ユーザ名とパスワードが送られてきた時には、ユーザ・アカウントのデータベ
ースをチェックしてください。このデータベースには、パスワードを「平文」
で保存しないでください。誰かがこのデータベースをコピーしてしまえば、ま
たたく間にすべての人間のパスワードを手に入れられます(おまけにユーザはよ
くパスワードを使いまわしします)。 crypt()を使って平文を扱う場合もありま
すが、crypt はちょっとした入力だけしか扱えませんので、別の方法を使用す
ることをお薦めします(これは私の解決方法で、 Fu [2001]ではこの点を論じて
いません)。そのかわりに、ユーザ・アカウントのデータベースでは、ユーザ名
とサルト(salt) そのユーザに対してのパスワードのハッシュを入れてください
。サルトはランダム・シーケンスな文字列で、攻撃者がパスワードの入ったデ
ータベースを入手したとしても、パスワードを割り出すのが困難にするために
使われます。 8 文字のランダム・シーケンスをお薦めします。これは暗号的に
ランダムである必要はありません。ただし他のユーザとは違った値にしてくだ
さい。パスワードのハッシュは、「server key1」とユーザのパスワード、サル
トをつなげて計算する必要があります。計算するのには、暗号的に安全なハッ
シュをつくるアルゴリズムを用います。 server key1 は秘密鍵で、このサーバ
に一意に与えられたものです。この鍵はパスワードのデータベースとは別にし
ておいてください。誰かが server key1 とパスワードの入ったデータベースを
手に入れれば、プログラムを動かしてユーザのパスワードをクラックできます
。パスワードを記憶しておく必要はありませんので、長くて複雑なものにして
おけます。最も安全なのは HMAC-SHA-1 か HMAC-MD5 です。 SHA-1(SHA-1 を使
うことで可能となる攻撃を、たいていの Web サイトではそれほど心配していま
せん) や MD5(後述の MD5 についての議論を見てください) も利用できます。

このように、ユーザがアカウントを作成する時、パスワードはハッシュされ、
パスワードを入れるデータベースへと登録します。ユーザがログインしようと
すると、パスワードとして入力されたものがハッシュされ、データベースにあ
るハッシュと比較します(等しくなければいけません)。ユーザがパスワードを
変更する時には、古いものと新しいもの両方を入力します。新しいパスワード
は 2 回入力します(ミスタイプしないように)。また一方で、パスワード文字列
が画面に出ないことを確認してください。

デフォルトで、クッキーを使ってパスワード自体をクライアント側のブラウザ
に保存しないでください。ユーザはクライアントを共同で利用している時があ
るかもしれません(たとえば、インターネットカフェのように)。望むなら、ユ
ーザにブラウザで「パスワードを保存する」選択を与えることもできますが、
そうするなら、パスワードは必ず「安全な」接続の伝送にだけ使うようにして
ください。またユーザがパスワードを保存することを確かに望んでいるかを確
認してください(デフォルトにしてはいけません)。

よく利用するページが決してキャッシュされないようにしてください。プロク
シサーバが他人にそのページを見せないようにしてください。

ユーザがログインに成功したなら、サーバはクライアントに「認証トークン」
をクッキーで送る必要があります。この点については次で述べます。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

10.2.2. Web の認証ログイン後の動作

ユーザがログインすると、サーバはクライアントに認証トークンとしてクッキ
ーを送り返します。推奨するトークンは下記のようになります。

  exp=t&data=s&digest=m                                                

t はトークンの有効期限(たとえば、数時間)とdata(たとえば、ユーザ名やセッ
ション ID)が入り、digest には鍵化したダイジェストが入ります。「data」の
フィールド名は変更自由で、もっとわかりやすい名前(たとえば、 username や
sessionid)にしてもかまいません)。鍵化したダイジェストは、有効期限を暗号
化したハッシュとデータを連結したものにしてください。データ・フィールド
が 2 つ以上あるなら(たとえば、username と sessionid 両方)、ダイジェスト
には認証をしているすべてのフィールドのフィールド名とデータ値を使うよう
にしてください。それらをあるパタンで連結してください(「%%」や「+」、「&
」)。またそのパタンがデータ値としてどのフィールドにも現れないようにして
ください。鍵化したダイジェストは、HMAC-MD5 か HMAC-SHA1 を使うようにし
て、別のサーバ側の鍵(key2)を用いてください。この key2 が信頼できないと
、誰もサーバ側で認証できなくなります。しかし key2 を変更するのは簡単で
す。変更した時は、「ログインした」ユーザに再認証をさせればよいだけです
。詳しくは Fu [2001] を見てください。

ログインした時からずっと、サーバは有効期間とこの認証に使われているトー
クンのダイジェストをチェックしてください。一致した場合にだけデータを提
供してください。トークンがなければ、ユーザにはログインするページを返し
てください(hidden フォームのフィールドがあって、ログインが成功した後に
飛ぶべきところを表示)。

セッション ID を認証トークンに入れると、アクセスがさらに制限できます。
サーバがあるセッションでユーザがどのページを見ているかを「追跡」できま
す。また、見てもかまわないページにだけアクセスを許可できます(たとえば、
それらのページから直接リンクされているものだけとか)。たとえば、あるユー
ザが foo.html というページへのアクセスを認められていて、 foo.html とい
うページには bar1.jpg と bar2.png というリソースを指しているところがあ
るとして、bar4.cgi へのアクセスを拒否できます。セッションを切ることさえ
も可能ですが、認証情報が正しいことが条件です(さもないと、攻撃者が他人に
対してサービス拒否攻撃をしかけられます)。たとえセッションの乗っ取りに成
功したとしても、これで攻撃者がかけてくるアクセスを多少なりとも制限でき
ます。しかし、攻撃者に攻撃する時間と認証トークンがあれば、通常ユーザが
するようにリンクを「渡り歩く」ことが可能です。

決め所は、認証トークンが必要なのか、それとも安全な接続(たとえば、SSL)で
データを送るのが必要なのか、それとも両者とも必要なのか、という点です。
認証トークンを暗号化せずに(安全ではなく)送ると、トークンを横取りすれば
、ユーザと同じことを有効期限が切れるまで実行できます。また、暗号化され
ていない接続でデータを送ると、ユーザが気付かないうちに攻撃者がデータを
変更してしまう危険があります。このようにデータを誰かが変更してしまうの
が心配なら、伝送するデータに認証をかけなければいけません。暗号化自体が
認証を受け持っているわけではありませんが、不正行為を発見しやすくなりま
す。また代表的なライブラリは TLS や SSL で暗号化と認証を両方ともサポー
トしています。一般的に、メッセージを暗号化したいなら、その認証もあわせ
て行ってください。要求が異なるなら、もう 1 つのやり方として認証トークン
を 2 つ作成する方法もあります。トークンの 1 つは「安全な」接続を行って
、重要な操作をする目的にだけ使用します。一方もうひとつのトークンは、そ
れほど重要でない操作に利用します。「安全な」接続のために使われるトーク
ンに注意を払って、安全な接続(暗号化した SSL か TLS 接続が一般的)にだけ
使われているようにしてください。ユーザが違っていたなら、認証トークンが
「データ」を完全に削除してください。

繰り返しになりますが、認証トークンをともなうページは、決してキャッシュ
されないようにしてください。他にも手ごろな方法があります。このドキュメ
ントの最終目標は少なくとも 1 つ、安全な解決方法を提供することです。可能
な解決方法はたくさんあります。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

10.2.3. Web の認証――ログアウト

「ログアウト」する仕組みをいつもユーザに提供してください。これはブラウ
ザを共有して使うユーザ(たとえば、図書館で)にとっては特に便利です。「ロ
グアウト」するルーチンの役目は単純です。クライアント側の認証トークンを
解除すればよいだけです。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

10.3. 乱数

安全が必要なプログラムは、攻撃者が推定できない「ランダムな」数(乱数)を
さまざまな場面で生成しなければいけません。たとえばランダムな数には、セ
ッション鍵を含む公開もしくは秘密鍵や対称鍵、さまざまなプロトコルで使用
している nonce(その時だけ有効な情報)や初期ベクトル(IV)、salt 等が該当し
ます。理想を言えば、乱数は真にランダムであるデータを元にすべきです。そ
のような値には、放射線崩壊(ガイガー・カウンターの雑音を正確に計測)や大
気の雑音、電気回路の熱雑音があります。コンピュータには、本物の乱数生成
器として機能するハードウェア部品を搭載するものもあります。利用できるも
のなら利用してください。

しかし、たいていのコンピュータには真に乱数を発生するハードウェアはつい
ていません。そこで乱数を発生させる方法が必要になるケースがほとんどです
。発生させる方法は、攻撃者が予想できない程度にランダムである仕組みが必
要になります。普通 3 つの仕組みが必要になります。

 ・ 「推測不可能な」状態。低レベルのデバイス(キー入力やディスク・ドライ
    ブのアームのジッタ(ゆれ)等)の変化を計測することで実現します。攻撃者
    はこれを制御できません。
   
 ・ 暗号用に強化した擬似乱数発生器(PRNG)。これは内部状態を使って「ラン
    ダム」な数を発生します。
   
 ・ 大きなビット数(シードと結果として使われた値の両方)。使える値がわず
    かなら、強力な PRNG を持っていても無駄です。理由は、攻撃者が総当た
    り攻撃をかけやすくなるからです。必要になるビット数は環境にもよりま
    すが、暗号鍵としても利用されているので、経験上、この鍵にもこのルー
    ルを適用します。対称鍵(とその結果)は、少なくとも 112 ビット(3DES)を
    使用しています。128 ビット使えば、多少ましになり、160 ビット以上な
    らより安全です。
   
通常、PRNG は内部状態を使って鍵を生成します。その値やその他の推測できな
い入力を使って状態を更新します。この仕組みを攻撃する方法はたくさんあり
ます。たとえば、攻撃者が状態への入力を制御したり、見たりしたりできれば
(部分的にでも)、攻撃者は「ランダムな」数をもしかすると割り出すかもしれ
ません。

PRNG が本当に危険なのは、コンピュータ言語のライブラリの大半に、擬似乱数
発生器 (PRNG)が備わっている点にあります。これはセキュリティ用には不適切
です。繰り返しましょう。標準的な乱数発生器をセキュリティ用に利用しない
でください。標準的な PRNG ライブラリはシミュレータやゲーム向け等に使わ
れるもので、鍵生成のようなセキュリティ向けのランダムさを十分に持ち合わ
せていません。暗号化していない PRNG ライブラリは、「線形合同法を用いた
発生器」系が多く、「次の」ランダムな値は「(aX+b)modm」(X は以前の値)と
して計算されます。線形合同法を用いた発生器として優れていれば、高速で有
効な統計的特性を持ち、目的とするところにぴったり当てはまります。そのよ
うな PRNG の問題点は、攻撃者が先々の値を簡単に推論できる点にあります
(ランダムに現れたとしても)。乱数を素早く生成する二次生成器や三次生成器
のようなその他のアルゴリズムもやられてしまいます[Schneier 1996]。つまり
、安全が必要なアプリケーションでは、暗号的に強固な PRNG を利用して、乱
数を生成しなければいけません。一般的な乱数ライブラリでは十分ではありま
せん。

鍵用に真の乱数を正しく生成できないと、問題がいろいろ発生します。
Kerberos や X Window System、NFS のセキュリティホールがそれです[Venema
1996]。

できるだけ、システムに用意されているサービスを使うべきです(一般的にはオ
ペレーティングシステムが用意しているもの)。そのようなサービスは、安全な
乱数を提供できるように特に設計して作られているからです。たとえば、Linux
カーネル(1.3.30 から)は乱数生成器を持っていて、セキュリティ用に十分対応
できます。この乱数生成器は、周囲で発生するノイズをデバイスドライバや他
の情報源から収集して、エントロピー・プールに収めます。 /dev/random にア
クセスするとエントロピー・プールにあるノイズから推定されたビット数の範
囲でだけ、ランダムな値が返されてきます(エントロピー・プールが空の場合は
、周囲からノイズが集まってくるまで、呼び出しをブロックします)。 /dev/
urandom でアクセスして、大きな値を要求すると、エントロピー・プールが使
い果たされても値が返ってきます。乱数を暗号化の目的で利用するなら(たとえ
ばキーの生成のため)、/dev/random を使ってください。 BSD系システムも /
dev/random を持っています。 Solaris は SUNWski パッケージで /dev/random
を用意しています。ハードウェアの乱数生成器が利用可能なら、ドライバをイ
ンストールしてかわりに利用してください。さらに詳しい情報は、システムに
あるオンラインマニュアルの random(4)を参照してください。

システムによっては、真にランダムな結果を得るのに、他の手段を捜さなけれ
ばいけないものもあります。 Unix ライクなシステムで可能な方法の 1 つに
Entropy Gathering Daemon (EGD)があります。このデーモンはシステムの動作
を監視して、それをハッシュしてから乱数にします。このデーモンは、 http:/
/www.lothar.com/tech/crypto から取得できます。 PRNG の出力として、暗号
化ハッシュ機能(たとえば、SHA-1)の利用も検討してもよいと思います。ハッシ
ュアルゴリズムを使えば、PRNG の出力が推測できるようになったとしても、攻
撃者は、さらにハッシュ機能も片づけなければならないからです。

自分で強力な PRNG を実装しなければならないなら、暗号的に強固な(かつ特許
に抵触しない) PRNG である Yarrow アルゴリズムを採用するのが良いでしょう
。Yarrow については http://www.counterpane.com/yarrow.html でさらに知る
ことができます。 PRNG には他にも便利に使えるものがありますが、広く利用
されているものには既知の弱点を持つものがあり、アプリケーションによって
は問題になる場合も考えられます。 PRNG を自分で実装する前に [Kelsey
1998] や [McGraw 2000a]のような文献を調べてください。 IETF RFC 1750
<http://www.ietf.org/rfc/rfc1750.txt> も調べた方が良いでしょう。【訳註
：IETF RFC 1750 の日本語訳は、 http://www.ipa.go.jp/security/rfc/
RFC1750JA.html にあります】

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

10.4. ユーザ空間ではとりわけ秘密(パスワードや鍵)を守る

アプリケーションがパスワードや非公開鍵(セッション鍵や秘密鍵)を扱う必要
があるなら、公開を最小限にとどめるために、使用後はすぐに上書きしてくだ
さい。たとえば、Java では String 型にパスワードを保存しないでください。
String 型は変更されないからです(ガーベジコレクトされるか、再利用されな
い限り、上書きされません。こうなるには時間がかかるでしょう)。 String 型
のかわりに、char[] を使ってパスワードを保存してください。そうすればすぐ
に上書きされます。

また、プログラムがそのような秘密の値を扱うなら、コアダンプを絶対作らな
いようにしてください(ulimit を使って)。さもないと攻撃者がプログラムを中
断させて、ダンプしたデータから秘密の値を見つけ出すかもしれません。もう
1 つ注意しなければならない点があります。それは、一般プロセスがデバッガ
ー (たとえば、ptrace(2)を使ったり、/proc の擬似ファイルシステムを使った
りして)を呼び出すことで、他のプロセスを監視できる点です[Venema 1996]。
カーネルは通常、そのプロセスが setuid もしくは setgid してあるとそのよ
うな監視ルーチンからプロセスを保護します(古いカーネルでは保護が働きませ
ん。保護するためにはアップグレードするしか方法はありません)。つまり、プ
ロセスが秘密の値を扱うなら、そのプログラムに(特権を持たないグループやユ
ーザで)setuid もしくは setgid をかけて、この種の監視を強制的に禁止する
ようにしてください。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

10.5. 暗号化アルゴリズムとプロトコル

暗号化アルゴリズムやプロトコルは、システムの安全を維持するのに必要です
。インターネットのように信頼できないネットワークを経由して通信する場合
は、特に必要になります。できるだけ暗号技術を使って情報を認証し、秘密を
維持してください(しかし、暗号化が認証を自動的にうまく行ってくれると、単
純に思いこまないでください)。一般的には、適切なツールを使ってアプリケー
ションを安全にする必要があります。

これまでの背景を知りたければ、著名なテキストである「Applied
Cryptography」 [Schneier 1996]を読んでください。「sci.crypt」ニュースグ
ループは、FAQ を逐次出しています。あちこちで手に入りますが、http://
www.landfield.com/faqs/cryptography-faq にもあります。 Linux Encryption
HOWTO を含む Linux 固有の情報元は http://marc.mutz.com/Encryption-HOWTO
/ です。プロトコルがどのような基本的アルゴリズムを利用しているかについ
ては、 [Opplinger 1998]を見てください。プロトコルにどうやって暗号を適用
するかについては、ドキュメントのコレクションとして [Stallings 1996]があ
ります。ここでわずかですが、解説をします。特化した内容になっていますの
で、より広く知りたいならば、別のところを参照してください。

暗号化したプロトコルや暗号アルゴリズムを正しく理解するのは困難なので、
自分で作ろうとはしないでください。そのかわりに、広く利用され、念入りに
解析されたプロトコルやアルゴリズムを利用してください。それが安全なもの
と理解してください。暗号に関連したものを作成しなければならない時には、
レビューを広く公開し、セキュリティ分析の専門家が問題を調査できるように
しなければいけません。自分が暗号化の専門家で、何をしているかを把握し、
何年もかけてアルゴリズムの専門家のレビューを受ける計画を立てられなけれ
ば、暗号アルゴリズムを作成するようなことはしないでください。 (いくらか
でも役に立つ)暗号アルゴリズムの作成は、専門家だけに許された作業です。

アルゴリズムの多くは特許を取っています。所有者が「利用は自由」、とある
時点で認めていたとしても、契約書に署名をしていなければ、所有者の気持ち
が後になって変わって、後で多大なリスクを背負うことになります。総じて特
許のあるアルゴリズムはすべて避けてください。ほとんどどんなケースでも、
特許に抵触しない解決方法があります。またその解決方法は、少なくとも特許
を持つものと同等か、それ以上に優れた技術を使っています。そうしておけば
、法的な問題の数々を回避できます。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

10.5.1. 暗号化プロトコル

プロトコルは標準で適応している SSL(まもなく TLS に)や SSH、IPSec、GnuPG
/PGP、 Kerberos 等を使うようにしてください。機能のいくつかはそれぞれに
かぶっていますが、おのおの「得意の」分野を持っています。 SSL(まもなく
TLS)は、そもそも http(Web)のやり取りを保護する手法です。 PGP 互換プロト
コル(PGP や GnuPG で実装)は、そもそも端末相互間で安全な電子メールをやり
取りする方法です。 Kerberos は本来、LAN 上で認証を安全にサポートする方
法です。また、秘密を共有する仕組みを構築します(つまり、実際に通信を保護
するアルゴリズムは別に必要になります)。 SSH はそもそもインターネット越
しに「離れた端末」を安全にする方法です。たとえば、telnet や X Window
System のようなものを対象にしています。しかし他のデータ・ストリーム(CVS
へのアクセスのような)を安全にする場合にも良く使われています。 SSH プロ
トコルにはメジャーな 2 つのバージョンが存在していることに注意してくださ
い。また鍵のタイプ等の選択肢がいくつかあることにも注意してください。詳
しい情報はそれぞれのドキュメントを参照してください。 OpenSSH は、SSH の
オープンソース版実装の 1 つです。 IPSec はそもそも低レベルでパケット「
すべて」を安全にする方法です。したがって、仮想プライベート・ネットワー
ク(VPN)や離れたところにあるマシンを安全にするのに便利です。インターネッ
ト・プロトコルの新しいバージョンである IPv6 は IPSec を「組み込んで」い
ますが、より一般的な IPv4 でも IPSec は動作します。

さまざまなプロトコルで、いろいろなアルゴリズムが利用できます。したがっ
てデフォルトとして、適切なアルゴリズムを選択する必要があります(たとえば
、暗号化アルゴリズム)。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

10.5.2. 対称鍵の暗号化アルゴリズム

暗号アルゴリズムの利用や輸出入は、国で規制されているケースが多く、かつ
法律は刻々と改定されます。暗号を使ってアプリケーションを構築しようとす
る前に、法律がどうなっているかを調査してください。

秘密鍵(巨大なデータです)の暗号化アルゴリズムは、オープンに公開されてい
て、長年の攻撃に耐え続けたものだけを利用してください。特許の状態も調べ
てください。私としては、Rijndahl として有名な Advanced Encryption
Standard(AES)の利用を推奨します。大勢の暗号研究者がこれを解析して、重大
な弱点が見つけられないことがわかっています。私は、現状では十分に信頼す
るに足ると信じています。 AES のかわりとして優れているものは、Serpent ア
ルゴリズムです。このアルゴリズムは処理が少々低速ですが、攻撃に対してと
ても強力です。アプリケーションの多くにとって、triple-DES は非常に優れた
暗号アルゴリズムです。鍵長も適度で(112 ビット)、特許問題もありませんし
、攻撃に長年耐えてきた実績があります(公開資料があり、適度な鍵長を持った
暗号化アルゴリズムの中で、これほど長い期間攻撃に耐えてきたものは他にあ
りません)。しかし、triple-DES はソフトウェアで実装してあると非常に低速
で、triple-DES は「安全だが遅い」と思われています。 Twofish は優れた暗
号アルゴリズムですが、なかなかある疑いがぬぐえません。それは、Sean
Murphy 氏と Fauzan Mirza 氏が Twofish はたくさんの学者が所有権を持って
いる、としている点です(しかし今のところ誰もその所有権を犯そうとはしてい
ません)。 MARS は「新手の斬新な」攻撃に対して抵抗力が強力です。しかし、
より複雑で、低性能 IC カードで対応するのは非現実的です。今のところ、私
は Twofish を採用しません。理由は、確かに Twofish は決してやられること
はないと思われますが、しがらみを確認するのが困難だからです。しがらみが
ないアルゴリズムが他にも存在していますので。 IDEA は使わないでください
。米国と欧州の特許にしばられています。定数や文字定数を XOR したようなも
のや ROT(転置暗号)法やビジネル暗号等、考えなしなアルゴリズムを使わない
でください。これらは現在のコンピュータならわけもなく破れます。「double
DES」(DES を 2 度かける)は使わないでください。 triple-DES では起こらな
い「man in the middle 攻撃」にやられやすいからです。とにかく、プロトコ
ルが複数の暗号アルゴリズムをサポートしているようにしてください。そうす
れば、ある暗号アルゴリズムがやられても、ユーザは別のアルゴリズムに変更
できますので。【訳註：「man in the middle 攻撃」については、二つの MITM
って？ <http://www.vicus-oryzae.com/gorua/mitm.html> が参考になります】

対称鍵の暗号化(たとえば、巨大な暗号向けに)には、もし 2016 年まで秘密を
保ちたいなら、90 ビットより小さい鍵長を利用しないでください(さらにビッ
トを増やせば、ビット毎に 18 か月セキュリティを保持する期間が増えます)
[Blaze 1996]。それほど重要でないデータを暗号化するなら、以前からある
DES アルゴリズムが役立つ場合があります。しかし最近のハードウェアならい
とも簡単に総当たり攻撃で DES の 56 ビット鍵を破れます。 DES を使ってい
るなら、鍵として ASCII テキストを使わないようにしてください。パリティは
最下位(最上位ではない)ビットにありますし、DES アルゴリズムの多くは、攻
撃者がよく知ってしまっている鍵値を使って暗号化しています。そのかわり、
鍵のハッシュを作成し、間違いなくパリティ・ビットに設定してください(暗号
化ルーチンが出すエラーメッセージには注意を払ってください)。いわゆる輸出
向け暗号アルゴリズムは、有効な鍵長がたった 40 ビットになっています。こ
れでは意味がありません。 1996 年には攻撃者は 10,000 ドルを費やして 12
分でそのような鍵を破りましたし、コンピュータが空いている時間を使って数
日で鍵を破りました。どちらのケースも、破られるのに 18か月の半分の時間を
持っていたのにです。

ブロック暗号化アルゴリズムは、いろいろなモードを使っています。たとえば
、「electronic code book」(ECB)や「cipher block chaining」(CBC)がそれで
す。 CBC を利用するのが一般的ですが、ECB モードは使わないでください。
ECB モードでは、あるストリームで、同じデータブロックが常に同じ結果を返
します。これでは暗号化されたものが何なのか、公表しているようなものです
。 CBC モードを含むモードは、「初期ベクトル」(IV)を必要とする場合が多く
あります。 IV を秘密にする必要はありませんが、攻撃者が予測できるようで
はいけません。セッションをまたがって IV を再利用してはいけません。セッ
ションをはじめる度に、新しい IV を使ってください。

ストリーム暗号アルゴリズムはいろいろありますが、大部分が特許に縛られて
います。特許に引っかからず、技術的に問題の無いものに、WAKE があります。
RC4 は RSA Data Security Inc の企業秘密でした。しかし漏洩してしまったの
で、その利用に現実的な法的障害があるとは思えません。しかし RSA はその利
用者に対して法的処置を施すと、主張を続けてきました(RSA ができることが何
なのか、はっきりしていません。しかしユーザが無意味な裁判沙汰に巻き込ま
れる可能性があるのは疑いようもありません)。 RC4 を使うなら、自覚して利
用してください。特に RC4 が生成した最初の 256 バイトは切り捨ててくださ
い。さもないと脆弱さを抱えることになります。 SEAL は IBM が特許を持って
います。したがって利用しないでください。 SOBER には特許があります。特許
の所有者は、利用許可を取ってくれれば自由に使ってかまわないとしています
が、後々の利用の障害になります。さらに面白いのは、モードでブロック暗号
アルゴリズムを利用できる点です。ブロック暗号アルゴリズムをストリーム暗
号のように扱います。ストリーム暗号を使いたいユーザは、この解決方法を検
討してください(もっと広く公開しているアルゴリズムから選ぶこともできま
す)。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

10.5.3. 公開鍵アルゴリズム

公開鍵暗号法(秘密鍵に署名し、それを送る場合に特に利用されています)で、
広く利用されているアルゴリズムはほんのわずかです。広く利用されているア
ルゴリズムに、RSA があります。 RSA のアルゴリズムには特許があります。し
かしそれは米国に限定されますし、 2000 年 9 月に特許が切れますので、自由
に使えます。決して生の値を復号したり、署名したりしないでください。攻撃
者は RSA を使って直接生の値を渡し、その結果を公開します。こうすることで
、秘密鍵を公開できるからです(実際にはこれは問題にはなりません。プロトコ
ルの大部分は、ユーザ側で計算したハッシュに署名したものが入っているから
です。これは生データではありません。つまり結果は公開されません)。まった
く同じ生の値を何回も復号したり、署名したりは絶対しないでください(元の値
が公開されてしまうかもしれません)。常に双方にランダムなパディングを追加
すれば、解決できます(PGP はそうしています)。普通この解決方法を Optimal
Asymmetric Encryption Padding (OAEP)と呼んでいます。

Diffie-Hellman 鍵交換アルゴリズムは、2 者間でセッション鍵を一致させる場
合に広く利用されています。それ自身では、お互いに誰であるかの保証はして
いませんので、仲介者は存在しません。しかし、盗み聞きを防ぐのには、非常
に効果があります。特許は 1997 年に切れました。 Diffie-Hellman を使って
共有鍵を作成したいなら、はじめに必ずハッシュしてください (共有値を直接
使った攻撃方法が存在します)。

NIST は digital signature standard (DSS)を開発しました(ElGamal 暗号シス
テムの改良版です)。これは電子署名の生成と認証を目的としています。開発条
件の 1 つに、特許は取らない、とあります。 

RSA や Diffie-Hellman、El Gamal 法は、代表的な対称鍵と比べて、同等のセ
キュリティを実現するのにさらにビット数を要します。 1024 ビット鍵が 80
ビットの対称鍵とおおよそ同等です。私の考えでは、このビット数は現在必要
な最低ラインです。公開鍵をごくわずかなビット数にする必要があるなら、
elliptic curve 暗号(楕円曲線暗号)を利用しても良いでしょう(IEEE P1363 で
は曲線をいくつか推奨しています。適切な曲線を見つけるのは困難です)。しか
し注意すべき点があります。elliptic curve 暗号には特許はありませんが、そ
の高速化技術に特許がある点です(elliptic curve 暗号は十分に高速で、これ
らの高速化は実際に普通の暗号セッションや巨大な暗号鍵の利用には必要あり
ません)。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

10.5.4. 暗号化ハッシュ・アルゴリズム

一方向ハッシュ暗号アルゴリズムが必要なプログラムもあります。つまり「任
意の」量のデータを受け取って、攻撃者が逆転するのが困難な固定長の数を生
成する関数です (たとえば、攻撃者が別のデータを使って、同じ値を生成する
のが困難なものです)。もう何年も MD5 が本命でしたが、最近の成果で MD5 の
128 ビット長ではもはや十分でないことが示されました[van Oorschot 1994]。
また、ある種の攻撃は MD5 の防御を弱体化します[Dobbertin 1996]。業界トッ
プの暗号家が MD5 を破ったが、雇用契約の関係で沈黙している、という噂が実
際にあります(John Viega 氏が Bugtraq に August 2000 年 8 月 22 日に投稿
した記事を見てください)。噂は誰でも流せますが、弱点がそれなりに見つかっ
ていますので、完璧に破ったというのはもっともらしく聞こえます。新しくコ
ードを書くなら、MD5 のかわりに SHA-1 を使ってください。オリジナルの SHA
(SHA-0 と呼ばれています) は使わないでください。 SHA-0 は MD5 と同じよう
な弱点があります。ハッシュアルゴリズムにもっとビット数が必要なら、
SHA-256 や SHA-384、SHA-512 を使ってください。仕様書は、NIST の FIPS
PUB 180-2 にあります。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

10.5.5. 整合性の確認

通信をする時には、何らかの整合性のチェックが必要です(暗号化にだけ頼らな
いでください。攻撃者が情報を変更して、「ランダム」な値にしてしまえます)
チェックはハッシュアルゴリズムで実現できます。しかし、直接ハッシュ関数
を使用しないでください(そうすると、ユーザを「拡張」攻撃にさらすことにな
ります。攻撃者がハッシュ値を利用して、自分が選んだデータを追加し、新し
いハッシュを計算する攻撃です)。解決方法は、普通は「HMAC」です。これで整
合性のチェックを次のように計算します。

  H(k xor opad, H(k xor ipad, data)).                                  

H はハッシュ関数です(普通は MD5 か SHA-1 です)で、k は鍵です。つまり、
整合性の確認は、HMAC-MD5 か HMAC-SHA-1 になります。 MD5 は弱点を抱えて
いるものの、この構成では脆弱性は無いと思っています。したがって、
HMAC-MD5 は(私の考えでは)問題ありません。詳細は、IETF RFC 2104 に定義し
てあります。

HMAC による解決方法では、受信者が送信者となって同じデータを偽造できるこ
とを忘れないでください。これは普段問題にはなりません。しかし回避しなけ
ればならないなら、公開鍵方式を使って、送信者が送信者の秘密鍵で「署名」
して下さい。これで偽造による攻撃は回避できますが、より手間がかかってし
まいます。たいていの環境では必要ではありません。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

10.5.6. その他暗号関連の問題

暗号化とデータの整合性双方をチェックしてください。それが重要です。暗号
化に整合性のチェックがあったとしても、それに頼ってはいけません。攻撃者
がビットを変更して、別の値にしてしまうかもしれません。特定の値に変更で
きないとしても、その値を変更できればそれで十分です。普通は、手の込んだ
攻撃を回避するために、整合性と秘密維持に別の鍵を使ってください。

十分に議論できていない問題の 1 つに「トラフィック分析」があります。つま
りメッセージが暗号化され、その暗号が破られていなくても、攻撃者は暗号化
したメッセージからさまざまなことが分かってしまいます。たとえば、2 つの
会社の社長が、多数の暗号化された電子メールのメッセージをやり取りしはじ
めたとすると、 2 つの会社が合併を検討しているかもしれません。別の例とし
て、SSH の実装の多くにはパスワード交換の弱点があることが分かっています
。観察者はパケットを見て、パスワード長(もしくは長さの範囲)を推測できま
す。パスワード自体は推測できないにしてもです。また、パスワードに関連し
たその他の情報も推測できます。これはパスワードを破るのにかなりの手助け
となります。

部分的に問題を解決するような真似はしないでください。信頼できる環境(誰を
信頼できるか)が変化したなら、別の鍵を使ってください。あまりに長い間同じ
鍵を使わないでください。つまり、セッション鍵やパスワードは変更してくだ
さい。そうすれば、攻撃者は振りだしに戻らなければならなくなります。

概して何かを暗号化したいなら圧縮すべきです。これは固定長のへッダーを加
えることになり、必ずしも良いとは言えないのですが、メッセージを小さくす
るのと同時に、メッセージの残りにあるいくつものパタンも無くします。圧縮
した結果が小さくなりそうなら、普通は「うまくいった」と考えても良いでし
ょう。

関連事項として、自分で通信プロトコルを作成しなければならないなら、以前
どんな問題があったのか調査をしてください。 Bellovin[1989]のような TCP/
IP プロトコルのセキュリティ上の問題を論じた古典が役に立つと思います。
Bruce Schneier [1998]や Mudge 氏による Microsoftの PPTP の実装を破った
資料やその後の資料も同様です。繰り返しますが、新しいプロトコルはどんな
ものでも、必ず広く公開してレビューを受けてください。利用できるものは利
用してください。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

10.6. PAM を使う

Pluggable Authentication Modules(PAM)は、ユーザの認証を柔軟に行う仕組み
です。 Unix ライクなシステムには PAM をサポートしているものが多く、
Solaris や Linux ディストリビューションの大半(Red Hat Linux や Caldera
、Debian のバージョン 2.2)と FreeBSD 3.1 でサポートしています。 PAM を
使うと、プログラムと認証の仕組み(パスワードや IC カード)を独立したもの
にできます。つまり、プログラムは PAM を呼び出し、PAM がローカルシステム
の管理者が設定した内容をチェックし、どの「認証モジュール」が必要かをラ
ンタイムに判断します。認証が必要となるプログラム(たとえばパスワードを入
力する)を作成しているなら、 PAM を採用すべきです。 Linux-PAM プロジェク
トについては、 http://www.kernel.org/pub/linux/libs/pam/index.html を見
てください。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

10.7. ツール

セキュリティ上の問題を、実環境で結果を出す前に検出するツールが存在しま
す。もちろん、すべての問題を見つけられるわけではありませんが、巧妙で見
落としがちな問題を見つけてくれます。ここでは、オープンソースとフリーソ
フトウェアに焦点を当て、ツールを紹介します。

ツールのタイプの 1 つは、ソースコードを調べて、セキュリティ上問題になり
そうな既知のパタンを検索するプログラムです(たとえば、何らかの手段でライ
ブラリ関数を呼び出すことが、セキュリティ上の脆弱性につながります)。この
種のプログラムは「ソースコード・スキャナ」と呼ばれています。ここでいく
つか紹介します。

 ・ RATS (Rough Auditing Tool for Security)は、Secure Software
    Solutions によるもので http://www.securesw.com/rats から取得できま
    す。このプログラムは C と C++ のソースコードによく発生する問題をス
    キャンします。ライセンスは GPL です。
   
 ・ Flawfinder は私が開発したもので、 http://www.dwheeler.com/
    flawfinder から取得できます。これも C と C++ のソースコードによくあ
    る問題をスキャンします。ライセンスはやはり GPL です。 RATS との違い
    は、Python で実装している点です。 RATS と Flawfinder の開発者は、共
    同で最善の組み合わせのプログラムをオープンソースで産み出すことに合
    意しています。
   
 ・ ITS4 は Cigital(前 Reliable Software Technologies。略称 RST)による
    もので、同じく静的に C と C++ のコードをチェックします。商用に使わ
    なければ自由に利用でき、ソースコードも利用できます。修正や再配布も
    可能です。ただ、これは「オープンソース」を定義した Open Source
    Definition <http://www.opensource.org/osd.html> (OSD)でリリースして
    いるわけではありません。特に OSD の 6 番目の基準がオープンソースの
    ライセンスとして「商用目的での利用の禁止」条項を禁止しています。
    ITS4 は http://www.rstcorp.com/its4 から取得できます。
   
 ・ LCLint は静的に C プログラムをチェックするツールです。手間をほとん
    どかけなくても、LCLint は優れた lint として利用できます。さらに努力
    してプログラムに注釈を加えれば、LCLint は標準的な lint が行うどんな
    チェックより強力にチェックを行います。たとえば、バッファオーバーフ
    ローが起こりそうなところを静的に検出するのに利用できます。ソフトウ
    ェアのライセンスは GPL で、 http://lclint.cs.virginia.edu から取得
    できます。 
   
 ・ cqual は型ベースで分析するツールで、C プログラムのバグを見つけ出し
    ます。cqual は C の型システムを拡張して、さらにユーザ定義の型修飾子
    を追加しています。たとえば、「tainted」や「untainted」というように
    値を記述できます(Perl の汚染チェックと似ています)。プログラマはプロ
    グラムに何ヶ所か注釈を入れると cqual は修飾子から推論を行い、修飾子
    が適切かどうかチェックします。cqual は分析結果を Program Analysis
    Mode という emacs ベースのインタフェースを使って表示します。 cqual
    の現バージョンは、C プログラムの書式文字列の脆弱性がありそうな部分
    を検知できます。前バージョンの cqual である Carillon は、C プログラ
    ムにある Y2K 関連のバグを見つけるのに利用されました。ソフトウェアは
    GPL ライセンスで、 http://www.cs.berkeley.edu/Research/Aiken/cqual
    から取得できます。
   
 ・ Cyclone は C ライクな言語で、C のセキュリティ上の弱点を排除するのが
    目的です。ある言語から「もっと安全な」言語に理屈上はいつでも移行で
    きます。しかし、これは何にでも役に立つわけではありません(言語はよく
    ある間違いを回避するのに役立つかもしれませんが、あなたの考えを汲み
    取ってくれるわけではありません)。 2001 年 12 月に John Viega has
    reviewed Cyclone <http://www.securityfocus.com/guest/9094> で John
    Viega 氏は次のように述べています。「Cyclone が美しい言語であること
    はまぎれもない事実です。 C 系の言語であり、C の持つどんなパワーも失
    ってはいません。にもかかわらず、安全性を確固とすることを約束し、プ
    ログラマが本当に重宝できるさまざまな機能も加わっています。ただ残念
    なのは、Cyclone はまだ主流となるべく準備が整っているわけではない点
    です。制限を無くしながらも、まだ Java(もしくは便利なツールを使った
    C)を越えるような優位性を提供できていないので、この未熟な技術を使う
    リスクを負う価値はありません。もちろん数年の内に Cyclone は能力の点
    で C に恐ろしく近くありながら、成熟して強固になり、広くサポートされ
    る言語になるでしょう。そのような日がくれば、きっと C を捨てても良い
    と思うでしょう」。 Cyclone コンパイラは、GPL と LPGL でライセンスさ
    れています。さらに詳しい情報は、 Cyclone web site <http://
    www.research.att.com/projects/cyclone> を見てください。
   
別の解決方法にテストパタンを作成して、プログラムを動かす方法があります
。これはプログラムが持つ弱点を見つける試みの 1 つです。ツールがいくつか
あります。

 ・ BFBTester(Brute Force Binary Tester)は、GPL ライセンスです。このプ
    ログラムは迅速にバイナリプログラムに対してセキュリティ上のチェック
    を行います。 BFBTester はコマンドラインの単独もしくは複数の引数や環
    境変数のオーバーフローをチェックできます。バージョン 2.0 以上ではテ
    ンポラリファイルの作成をしようとする動作も監視できるようになりまし
    た(安全でないテンポラリファイル名が使われていないかチェックします)
    。以前は BFBTester は Linux では動きませんでした(Linux の POSIX ス
    レッドの実装による技術的な問題で)。しかし、バージョン 2.0.1 ではフ
    ィックスしています。さらに詳しい情報は、 http://
    bfbtester.sourceforge.net/ を参照してください。
   
 ・ fuzz <http://fuzz.sourceforge.net> は他のソフトウェアをテストするツ
    ールです。このテストは、ランダムなデータでプログラムを攻撃してテス
    トしながら評価します。セキュリティに限定したツールではありません。
   
動作しているプログラムを覗いて、コードにあるセキュリティ上の問題を発見
しようとするツールがたくさん存在します。このツールに該当するのは、シン
ボリックデバッガ(gdb のような)やトレースするプログラム(strace や ltrace
のような)です。おそらくあまりご存じないと思いますが、 Fenris <http://
razor.bindview.com/tools/fenris> (GPL ライセンス)というプログラムがあり
ます。ドキュメントには Fenris のことを「バグトラックを簡単にするために
、状態を保存して分析したり、部分的に逆コンパイルする機能を持ったりした
、汎用トレーサです。セキュリティ監査やコード、アルゴリズム、プロトコル
を分析します。プログラム構成のトレースや内部構造一般の情報として実行パ
ス、メモリ操作、入出力、条件式等々を提供します」とあります。もう 1 つこ
の系列で興味深いプログラムがあります。それは Subterfugue です。

一般的に弱点を抱えがちな製品(ftp サーバやファイアーウォール)を構築して
いるなら、セキュリティをスキャンするツールが役立つのはおわかりだと思い
ます。優れたものの 1 つに Nessus <http://www.nessus.org> があります。他
にもたくさんのツールがあります。この種のツールはリグレッション・テスト
(回帰テスト)を行うのに非常に便利です。そもそも過去に特定している脆弱性
のリストを使っているからです。ただし、新しいプログラムの問題を発見する
のには、役に立つとはいえません。【訳註：リグレッション・テストとは、プ
ログラムのあるバグを直した副作用で、また別のバグが発生していないかどう
か、確かめるテストを指します】

他のツールを呼び出して、基盤を安全に実装する必要が出てくるケースがよく
あります。 Open-Source PKI Book <http://ospkibook.sourceforge.net> には
、公開鍵基盤(PKI)実装用に、オープンソースのプログラムがたくさん載ってい
ます。

もちろん、安全でないプラットフォームの設定で「安全な」プログラムを動か
すのはほとんど意味がありません。よろしければ、システムを強固にする方法
を調査して、攻撃に対してより防御できるようにシステムを設定、もしくはカ
スタマイズしてください。 Linux ならば、 Bastille Linux が http://
www.bastille-linux.org で利用できます。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

10.8. Windows CE

Windows CE 機を安全にしたいなら、 Maricia Alforque 氏の「Creating a
Secure Windows CE Device」 http://msdn.microsoft.com/library/techart/
winsecurity.htm. を読んでください。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

10.9. 監査記録を書き込む

プログラムやセッション開始時、もしくは不審な動作がある時には、監査ログ
を書き込んでください。情報として、日付や時間、uid、euid、gid、egid、端
末情報、プロセス id、コマンドラインの値を取ってください。監査ログをとる
のに syslog(3)が役立つのはよく知られています。ログを採るシステムは、た
くさんの情報(非常に役立ちます)を記録できますが、その情報の取り扱いに注
意しないと、攻撃に利用されてしまう点がやっかいな問題です。最終的には、
攻撃者がプログラムに送る入力を部分的にコントロールします。攻撃者が送っ
たと思われるデータを記録した時に、「予想通り」の文字リストを設定し、「
予想通り」でない文字はみなエスケープしてください。そうすればログが汚染
されるようなことにはなりません。そうしないと、本当に困った事態になりま
す。たとえばユーザが制御文字(NIL や EOF) を入れると、やっかいな事態を発
生します。たとえば、攻撃者が改行を埋め込むと、好みのログを改行とともに
入れることで、ログの記録をねつ造できます。ひどい話ですが、これらの文字
のエスケープは、標準規格に沿っていないようです。私は URL エスケープが好
みですが(%hh の hh はエスケープするバイトの 16 進値です)、C の規格をは
じめとして、他のエスケープが存在します(\ooo は 8 進値で \X は X には特
別な符号が入ります。たとえば \n は改行です)。また、キャレットを使ったし
くみ(^I は control-I です)もありますが、127 より大きなバイト値はうまく
扱えません。 

ユーザがサービス拒否攻撃(もしくは少なくとも監査の停止)を引き起こす危険
性があります。その攻撃は、監査履歴を削除する多量のイベントを発生するこ
とで、システムが記録を保存するリソースを食い潰します。この攻撃に対する
対処方法の 1 つは、監査記録する速度に制限を設けることです。意図的に反応
速度を遅くし、「あまりに多くの」監査記録があれば削除します。攻撃の疑い
があるものに対してだけ、反応速度を遅くするようにしてください。しかし、
単独の攻撃者が複数ユーザであるかのごとく装っているケースがよくあります
。

もちろん何が「不審な動作」なのかを選択するのは、プログラムの動作と予定
していた使い方に左右されます。以前論じた入力のフィルタチェックに引っか
かったケースは、この対象となります (たとえば、NIL が入った)。通常利用に
由来しない入力は、おそらくログを採った方がよいでしょう。たとえば、必須
のフィールドがある CGI プログラムが怪しげに失敗する等。 /etc/passwd や
/etc/shadow のような書式は、怪しいケースがたくさんあります。同様に
Windows の「レジストリ」ファイルや .pwl ファイルにアクセスしようとする
のも不審です。

監査履歴にパスワードを記録しないでください。誤って、別のシステムにパス
ワードを入れてしまう場合がよくあります。そうすると、パスワードの記録が
あるシステムの管理者に、管轄外の別のコンピュータへの侵入を認めることに
なるかもしれません。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

10.10. 物理的な漏洩

このドキュメントの範疇を越えた話題ですが、コンピュータと通信機器はたく
さんの情報を漏らしていることを忘れないでください。この漏洩を本当に安全
なものとするのは困難です。電磁波盗聴に必要なものを知っている人はたくさ
んいます。コンピュータやディスプレイ、キーボード、その他盗聴できる部品
が放出する高周波を扱うものです。ディスプレイは、遠く離れたオフィスの壁
に反射したものでも盗聴可能です [Kuhn 2002]。モデムのライトで通信が行わ
れていることは十分にわかります。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

10.11. その他

下記の内容は、セキュリティ・ガイドラインなのですが、何処にも分類できな
いものです。

少なくとも前提条件の一部は、プログラムで事前にチェックしてください(たと
えば、プログラムが開始されるところで)。たとえば、あるディレクトリで「
sticky」ビットが立っていることを前提にしているなら、本当にそうなってい
るかをテストしてください。そのようなテストには時間はかかりませんし、そ
れによって深刻な問題を防げるはずです。もしそれぞれの呼び出しでテスト実
行時間がかかることが気になるなら、せめてインストール時に行うようにして
ください。アプリケーション起動時に行うとさらに良いです。

組み込みでスクリプト言語を使っているなら、その言語が環境変数を設定して
、スクリプトから実行されるプログラムに悪影響を与えるかもしれません。こ
れは防いでください。

複雑な設定用言語が必要なら、その言語にコメント文字があり、コメントアウ
トした安全な例がたくさんあるようにしてください。「#」はコメントとしてよ
く使われますが、これは「この行の残りはコメント」を意味します。

なるべく root に setuid や setgid したプログラムを作成しないでください
。かわりに、ユーザには root でログインするようにさせてください。

コードに電子署名をしてください。利用者は送られてきたものが利用できるも
のかどうかをチェックできます。

安全性が求められるプログラムを作成する場合は、静的にリンクを行うことを
検討してみてください。安全性が求められるプログラムが動的リンクを使わな
いようにすれば、動的なライブラリのリンク機能を狙った攻撃に対抗できます
。しかしこの方法には欠点もあります。使用するディスクやメモリが増える傾
向にあります(同じルーチンを複数個コピーするからです)。さらに悪いのは、
ライブラリの更新(たとえば、セキュリティの脆弱性を防ぐため) が面倒になる
なる点です。たいていのシステムでは自動的には更新できず、独自に更新を追
いかけて実装するしかありません。

コードを眺めている時には、条件にマッチしないケースすべてを検討してくだ
さい。たとえば switch 文があった場合、どのケースにもマッチしなかった場
合どうなるのか？「if」文があれば条件が偽になった場合にどうなるのか？な
どなど。

単にファイルを「削除」しても、ディスクからファイルのデータは除去されま
せん。システムの多くは、ただ「削除した」印をつけ、後で再利用できるよう
にします。またデータが一時的に他の所に置かれている場合もよくあります(メ
モリや swap ファイル、テンポラリ・ファイルとして)。実際、しつこい攻撃者
に対抗するには、データの上書きでは十分ではありません。磁気メディアを消
去する上での問題については、古典的なドキュメントである Peter Gutmann 氏
の「Secure Deletion of Data from Magnetic and Solid-State Memory」
<http://www-tac.cisco.com/Support_Library/field_alerts/fn13070.html> が
あります。しつこい攻撃者は、別の手段を使うこともできます。たとえば、コ
ンピュータから放出される電磁波を監視したり(軍事システムは、電磁波盗聴規
則に従い、これに対抗しています)、秘密裏に攻撃をかけます(キーボードに隠
した監視装置等)。

セキュリティ上の脆弱性を修正する時には、「警告」の追加を考慮し、(今修正
した) 脆弱性を侵そうとする試みを検知し、そのログを取るようにしてくださ
い。こうすることで、攻撃の機会を減らします。攻撃が進行していることがあ
らわになることで、特に攻撃者が攻撃できるかどうか、事前に調べる方法がな
くなります。つまり、脆弱性が侵入検知システムになるわけです。これは、認
証以前にサーバプログラムのバージョンを公開すると、セキュリティ上好まし
くないことも示しています。公開してしまうと、攻撃者がそのバージョンで動
作する攻撃に絞ってやすやすと攻撃できるからです。プログラムには、ユーザ
に対して故意にバージョンを「偽る」ことができるものがあります。そうする
と攻撃者は「間違った」攻撃をすることになり、攻撃を検出できます。脆弱性
はネットワークで起きるので、必ずセキュリティ・スキャナで脆弱性を検知で
きるようにしてください。 Nessus(http://www.nessus.org) と連絡をとって、
彼らのオープンソースなセキュリティ・スキャナが問題を検出できるかどうか
を確かめてください。そうすれば、ソフトウェア更新に無頓着なユーザは、セ
キュリティの脆弱性をスキャンすることで、問題を知ることになります(やるべ
きことをやるかもしれません)。

時には、このドキュメントのようなセキュリティガイドラインをレビューして
ください。せめて Chapter 11 にある結論は再読してください。そして気楽に
「はじめに」(Chapter 1)に戻って、再読しましょう。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

Chapter 11. 結論

                                    事の終わりは始めにまさる。気位が高 
                                    いよりも気が長いのがよい。         
                                                                       
                                       旧約聖書コヘレトの言葉 7 章 8 節
                                                                  (NIV)

Linux や Unix のような Unix ライクなシステムで、完璧に安全なプログラム
を設計・実装するのは、実際とても難しいことです。完璧に安全なプログラム
が難しい理由は、考えられる入力すべてに適切に対応し、敵意を持っているか
もしれないユーザが制御している環境に対しても、同様に対応しなければなら
ない点にあります。安全性が求められるプログラムの開発者は、使用している
プラットフォームについて深く理解し、ガイドライン(このドキュメント等)を
調べて適用し、品質を上げるプロセスを設けて(ピア・レビュー等)、プログラ
ムの脆弱なところを減らして行く必要があります。

ここでは結論として、このドキュメントで鍵となるガイドラインをいくつかあ
げておきます。

 ・ 入力をすべて検証してください。入力にはコマンドラインの入力や環境変
    数、CGI からの入力があります。「不正な」入力をただ拒否しないでくだ
    さい。何が「受け入れられる」入力なのかを定義して、マッチしないもの
    を拒否してください。
   
 ・ バッファオーバーフローを避けてください。プログラムが長い入力(と長い
    中間データ値)で絶対乗っ取られないようにしてください。現時点では、プ
    ログラミングでのエラーの代表格です。
   
 ・ プログラムの内部構成をきちんとしてください。インタフェースを安全に
    して、特権を最少にし、初期設定とデフォルトを安全にし、フェイル・セ
    ーフにしてください。競合状態を回避してください(たとえば、/tmp のよ
    うな共有ディレクトリで安全にファイルをオープンする)。信頼に足る経路
    だけを信じてください(たとえば、ほとんどのサーバは、セキュリティチェ
    ックや買い入れ価格のような機密データ類で、クライアントを信頼しては
    いけません)。
   
 ・ 注意深く他のリソースを呼び出してください。値を適切なものに制限し(特
    にメタキャラクタ関連)、システムコールの返り値は、すべてチェックして
    ください。
   
 ・ 慎重に情報を返してください。特に信頼できないユーザに対しては、フィ
    ードバックは最小限にし、出力が溢れていたり、反応が遅い場合にも対処
    してください。
   
 

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

Chapter 12. 参考文献

                                    賢者の言葉はすべて、突き棒や釘。た 
                                    だひとりの牧者に由来し、収集家が編 
                                    集した。それよりもなお、わが子よ、 
                                    心せよ。書物はいくら記してもきりが 
                                    ない。学びすぎれば体が疲れる。     
                                                                       
                                    旧約聖書コヘレトの言葉 12 章 11、12
                                                                節(NIV)

Web で利用できる技術的な論文があることを特に強調している点に注目してく
ださい。Web でこの種の技術情報の大部分が利用できます。

[Advosys 2000] Advosys Consulting (formerly named Webber Technical
Services). Writing Secure Web Applications. http://advosys.ca/tips/
web-security.html

[Al-Herbish 1999] Al-Herbish, Thamer. 1999. Secure Unix Programming FAQ
. http://www.whitefang.com/sup.

[Aleph1 1996] Aleph1. November 8, 1996. ``Smashing The Stack For Fun
And Profit''. Phrack Magazine. Issue 49, Article 14. http://
www.phrack.com/search.phtml?view&article=p49-14 or alternatively http:/
/www.2600.net/phrack/p49-14.html.

[Anonymous 1999] Anonymous. October 1999. Maximum Linux Security: A
Hacker's Guide to Protecting Your Linux Server and Workstation Sams.
ISBN: 0672316706.

[Anonymous 1998] Anonymous. September 1998. Maximum Security : A
Hacker's Guide to Protecting Your Internet Site and Network. Sams.
Second Edition. ISBN: 0672313413.

[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. ftp://ftp.auscert.org.au/pub/auscert/papers/
secure_programming_checklist

[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. http://www.research.att.com/~smb/papers/ipext.pdf

[Bellovin 1994] Bellovin, Steven M. December 1994. Shifting the Odds --
Writing (More) Secure Software. Murray Hill, NJ: AT&T Research. http://
www.research.att.com/~smb/talks

[Bishop 1996] Bishop, Matt. May 1996. ``UNIX Security: Security in
Programming''. SANS '96. Washington DC (May 1996). http://
olympus.cs.ucdavis.edu/~bishop/secprog.html

[Bishop 1997] Bishop, Matt. October 1997. ``Writing Safe Privileged
Programs''. Network Security 1997 New Orleans, LA. http://
olympus.cs.ucdavis.edu/~bishop/secprog.html

[Blaze 1996] Blaze, Matt, Whitfield Diffie, Ronald L. Rivest, Bruce
Schneier, Tsutomu Shimomura, Eric Thompson, and Michael Wiener. January
1996. ``Minimal Key Lengths for Symmetric Ciphers to Provide Adequate
Commercial Security: A Report by an Ad Hoc Group of Cryptographers and
Computer Scientists.'' ftp://ftp.research.att.com/dist/mab/
keylength.txt and ftp://ftp.research.att.com/dist/mab/keylength.ps.

[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. http://csrc.nist.gov/cc/
ccv20/ccv2list.htm

[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. http://www.cert.org/
advisories/CA-97.25.CGI_metachar.html.

[Clowes 2001] Clowes, Shaun. 2001. ``A Study In Scarlet - Exploiting
Common Vulnerabilities in PHP'' http://www.securereality.com.au/
archives.html

[CMU 1998] Carnegie Mellon University (CMU). February 13, 1998 Version
1.4. ``How To Remove Meta-characters From User-Supplied Data In CGI
Scripts''. ftp://ftp.cert.org/pub/tech_tips/cgi_metacharacters.

[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), http://
schafercorp-ballston.com/discex SANS 2000. http://www.sans.org/newlook/
events/sans2000.htm. For a copy, see http://immunix.org/
documentation.html.

[Cox 2000] Cox, Philip. March 30, 2001. Hardening Windows 2000. http://
www.systemexperts.com/win2k/hardenW2K11.pdf.

[Dobbertin 1996]. Dobbertin, H. 1996. The Status of MD5 After a Recent
Attack. RSA Laboratories' CryptoBytes. Vol. 2, No. 2.

[Felten 1997] Edward W. Felten, Dirk Balfanz, Drew Dean, and Dan S.
Wallach. Web Spoofing: An Internet Con Game Technical Report 540-96
(revised Feb. 1997) Department of Computer Science, Princeton
University http://www.cs.princeton.edu/sip/pub/spoofing.pdf

[Fenzi 1999] Fenzi, Kevin, and Dave Wrenski. April 25, 1999. Linux
Security HOWTO. Version 1.0.2. http://www.linuxdoc.org/HOWTO/
Security-HOWTO.html

[FHS 1997] Filesystem Hierarchy Standard (FHS 2.0). October 26, 1997.
Filesystem Hierarchy Standard Group, edited by Daniel Quinlan. Version
2.0. http://www.pathname.com/fhs.

[Filipski 1986] Filipski, Alan and James Hanko. April 1986. ``Making
Unix Secure.'' Byte (Magazine). Peterborough, NH: McGraw-Hill Inc. Vol.
11, No. 4. ISSN 0360-5280. pp. 113-128.

[Flake 2001] Flake, Havlar. Auditing Binaries for Security
Vulnerabilities. http://www.blackhat.com/html/win-usa-01/
win-usa-01-speakers.html.

[FOLDOC] Free On-Line Dictionary of Computing. http://
foldoc.doc.ic.ac.uk/foldoc/index.html.

[Forristal 2001] Forristal, Jeff, and Greg Shipley. January 8, 2001.
Vulnerability Assessment Scanners. Network Computing. http://
www.nwc.com/1201/1201f1b1.html

[FreeBSD 1999] FreeBSD, Inc. 1999. ``Secure Programming Guidelines''. 
FreeBSD Security Information. http://www.freebsd.org/security/
security.html

[FSF 1998] Free Software Foundation. December 17, 1999. Overview of the
GNU Project. http://www.gnu.ai.mit.edu/gnu/gnu-history.html

[FSF 1999] Free Software Foundation. January 11, 1999. The GNU C
Library Reference Manual. Edition 0.08 DRAFT, for Version 2.1 Beta of
the GNU C Library. Available at, for example, http://www.netppl.fi/~pp/
glibc21/libc_toc.html

Fu, Kevin, Emil Sit, Kendra Smith, and Nick Feamster. August 2001.
``Dos and Don'ts of Client Authentication on the Web''. Proceedings of
the 10th USENIX Security Symposium, Washington, D.C., August 2001. 
http://cookies.lcs.mit.edu/pubs/webauth.html.

[Gabrilovich 2002] Gabrilovich, Evgeniy, and Alex Gontmakher. February
2002. ``Inside Risks: The Homograph Attack''. Communications of the
ACM. Volume 45, Number 2. Page 128. 

[Galvin 1998a] Galvin, Peter. April 1998. ``Designing Secure
Software''. Sunworld. http://www.sunworld.com/swol-04-1998/
swol-04-security.html.

[Galvin 1998b] Galvin, Peter. August 1998. ``The Unix Secure
Programming FAQ''. Sunworld. http://www.sunworld.com/sunworldonline/
swol-08-1998/swol-08-security.html

[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. http://www.oreilly.com/
catalog/puis

[Garfinkle 1997] Garfinkle, Simson. August 8, 1997. 21 Rules for
Writing Secure CGI Programs. http://webreview.com/wr/pub/97/08/08/
bookshelf

[Gay 2000] Gay, Warren W. October 2000. Advanced Unix Programming.
Indianapolis, Indiana: Sams Publishing. ISBN 0-67231-990-X.

[Geodsoft 2001] Geodsoft. February 7, 2001. Hardening OpenBSD Internet
Servers. http://www.geodsoft.com/howto/harden.

[Graham 1999] Graham, Jeff. May 4, 1999. Security-Audit's Frequently
Asked Questions (FAQ). http://lsap.org/faq.txt

[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. http://language.perl.com/CPAN/doc/
FAQs/cgi/perl-cgi-faq.html

[Hall "Beej" 1999] Hall, Brian "Beej". Beej's Guide to Network
Programming Using Internet Sockets. 13-Jan-1999. Version 1.5.5. http://
www.ecst.csuchico.edu/~beej/guide/net

[ISO 12207] International Organization for Standardization (ISO). 1995.
Information technology -- Software life cycle processes ISO/IEC 12207:
1995.

[ISO 13335] International Organization for Standardization (ISO). ISO/
IEC TR 13335. Guidelines for the Management of IT Security (GMITS).
Note that this is a five-part technical report (not a standard); see
also ISO/IEC 17799:2000. It includes:

 ・ ISO 13335-1: Concepts and Models for IT Security
   
 ・ ISO 13335-2: Managing and Planning IT Security
   
 ・ ISO 13335-3: Techniques for the Management of IT Security
   
 ・ ISO 13335-4: Selection of Safeguards
   
 ・ ISO 13335-5: Safeguards for External Connections
   
[ISO 17799] International Organization for Standardization (ISO).
December 2000. Code of Practice for Information Security Management.
ISO/IEC 17799:2000.

[ISO 9000] International Organization for Standardization (ISO). 2000.
Quality management systems - Fundamentals and vocabulary. ISO 9000:
2000. See http://www.iso.ch/iso/en/iso9000-14000/iso9000/selection_use/
iso9000family.html

[ISO 9000] International Organization for Standardization (ISO). 2000.
Quality management systems - Requirements ISO 9001:2000

[Jones 2000] Jones, Jennifer. October 30, 2000. ``Banking on Privacy''.
InfoWorld, Volume 22, Issue 44. San Mateo, CA: International Data Group
(IDG). pp. 1-12.

[Kelsey 1998] Kelsey, J., B. Schneier, D. Wagner, and C. Hall. March
1998. "Cryptanalytic Attacks on Pseudorandom Number Generators." Fast
Software Encryption, Fifth International Workshop Proceedings (March
1998), Springer-Verlag, 1998, pp. 168-188. http://www.counterpane.com/
pseudorandom_number.html.

[Kernighan 1988] Kernighan, Brian W., and Dennis M. Ritchie. 1988. The
C Programming Language. Second Edition. Englewood Cliffs, NJ:
Prentice-Hall. ISBN 0-13-110362-8.

[Kim 1996] Kim, Eugene Eric. 1996. CGI Developer's Guide. SAMS.net
Publishing. ISBN: 1-57521-087-8 http://www.eekim.com/pubs/cgibook

[Kuchling 2000]. Kuchling, A.M. 2000. Restricted Execution HOWTO. http:
//www.python.org/doc/howto/rexec/rexec.html

[Kuhn 2002] Kuhn, Markus G. Optical Time-Domain Eavesdropping Risks of
CRT displays. Proceedings of the 2002 IEEE Symposium on Security and
Privacy, Oakland, CA, May 12-15, 2002. http://www.cl.cam.ac.uk/~mgk25/
ieee02-optical.pdf

[LSD 2001] The Last Stage of Delirium. July 4, 2001. UNIX Assembly
Codes Development for Vulnerabilities Illustration Purposes. http://
lsd-pl.net/papers.html#assembly.

[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.

[McKusick 1999] McKusick, Marshall Kirk. January 1999. ``Twenty Years
of Berkeley Unix: From AT&T-Owned to Freely Redistributable.'' Open
Sources: Voices from the Open Source Revolution. http://www.oreilly.com
/catalog/opensources/book/kirkmck.html.

[McGraw 1999] McGraw, Gary, and Edward W. Felten. December 1998. Twelve
Rules for developing more secure Java code. Javaworld. http://
www.javaworld.com/javaworld/jw-12-1998/jw-12-securityrules.html.

[McGraw 1999] McGraw, Gary, and Edward W. Felten. January 25, 1999.
Securing Java: Getting Down to Business with Mobile Code, 2nd Edition
John Wiley & Sons. ISBN 047131952X. http://www.securingjava.com.

[McGraw 2000a] McGraw, Gary and John Viega. March 1, 2000. Make Your
Software Behave: Learning the Basics of Buffer Overflows. http://
www-4.ibm.com/software/developer/library/overflows/index.html.

[McGraw 2000b] McGraw, Gary and John Viega. April 18, 2000. Make Your
Software Behave: Software strategies In the absence of hardware, you
can devise a reasonably secure random number generator through
software. http://www-106.ibm.com/developerworks/library/randomsoft/
index.html?dwzone=security.

[Miller 1995] Miller, Barton P., David Koski, Cjin Pheow Lee,
Vivekananda Maganty, Ravi Murthy, Ajitkumar Natarajan, and Jeff Steidl.
1995. Fuzz Revisited: A Re-examination of the Reliability of UNIX
Utilities and Services. ftp://grilled.cs.wisc.edu/technical_papers/
fuzz-revisited.pdf.

[Miller 1999] Miller, Todd C. and Theo de Raadt. ``strlcpy and strlcat
-- Consistent, Safe, String Copy and Concatenation'' Proceedings of
Usenix '99. http://www.usenix.org/events/usenix99/millert.html and 
http://www.usenix.org/events/usenix99/full_papers/millert/PACKING_LIST

[Mudge 1995] Mudge. October 20, 1995. How to write Buffer Overflows.
l0pht advisories. http://www.l0pht.com/advisories/bufero.html.

[Murhammer 1998] Murhammer, Martin W., Orcun Atakan, Stefan Bretz,
Larry R. Pugh, Kazunari Suzuki, and David H. Wood. October 1998. TCP/IP
Tutorial and Technical Overview IBM International Technical Support
Organization. http://www.redbooks.ibm.com/pubs/pdfs/redbooks/
gg243376.pdf

[NCSA] NCSA Secure Programming Guidelines. http://www.ncsa.uiuc.edu/
General/Grid/ACES/security/programming.

Neumann, Peter. 2000. "Robust Nonproprietary Software." Proceedings of
the 2000 IEEE Symposium on Security and Privacy (the ``Oakland
Conference''), May 14-17, 2000, Berkeley, CA. Los Alamitos, CA: IEEE
Computer Society. pp.122-123.

National Security Agency (NSA). September 2000. Information Assurance
Technical Framework (IATF). http://www.iatf.net.

[Open Group 1997] The Open Group. 1997. Single UNIX Specification,
Version 2 (UNIX 98). http://www.opengroup.org/online-pubs?DOC=007908799
.

[OSI 1999]. Open Source Initiative. 1999. The Open Source Definition. 
http://www.opensource.org/osd.html.

[Opplinger 1998] Oppliger, Rolf. 1998. Internet and Intranet Security.
Norwood, MA: Artech House. ISBN 0-89006-829-1.

[Paulk 1993a] Mark C. Paulk, Bill Curtis, Mary Beth Chrissis, and
Charles V. Weber. Capability Maturity Model for Software, Version 1.1.
Software Engineering Institute, CMU/SEI-93-TR-24. DTIC Number
ADA263403, February 1993. http://www.sei.cmu.edu/activities/cmm/
obtain.cmm.html.

[Paulk 1993b] Mark C. Paulk, Charles V. Weber, Suzanne M. Garcia, Mary
Beth Chrissis, and Marilyn W. Bush. Key Practices of the Capability
Maturity Model, Version 1.1. Software Engineering Institute. CMU/
SEI-93-TR-25, DTIC Number ADA263432, February 1993.

[Peteanu 2000] Peteanu, Razvan. July 18, 2000. Best Practices for
Secure Web Development. http://members.home.net/razvan.peteanu

[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
. http://www.go2net.com/people/paulp/cgi-security/safe-cgi.txt

[Quintero 1999] Quintero, Federico Mena, Miguel de Icaza, and Morten
Welinder GNOME Programming Guidelines http://developer.gnome.org/doc/
guides/programming-guidelines/book1.html

[Raymond 1997] Raymond, Eric. 1997. The Cathedral and the Bazaar. http:
//www.tuxedo.org/~esr/writings/cathedral-bazaar

[Raymond 1998] Raymond, Eric. April 1998. Homesteading the Noosphere. 
http://www.tuxedo.org/~esr/writings/homesteading/homesteading.html

[Ranum 1998] Ranum, Marcus J. 1998. Security-critical coding for
programmers - a C and UNIX-centric full-day tutorial. http://
www.clark.net/pub/mjr/pubs/pdf/.

[RFC 822] August 13, 1982 Standard for the Format of ARPA Internet Text
Messages. IETF RFC 822. http://www.ietf.org/rfc/rfc0822.txt.

[rfp 1999] rain.forest.puppy. 1999. ``Perl CGI problems''. Phrack
Magazine. Issue 55, Article 07. http://www.phrack.com/search.phtml?view
&article=p55-7 or http://www.insecure.org/news/P55-07.txt.

[Rijmen 2000] Rijmen, Vincent. "LinuxSecurity.com Speaks With AES
Winner". http://www.linuxsecurity.com/feature_stories/
interview-aes-3.html.

[Rochkind 1985]. Rochkind, Marc J. Advanced Unix Programming. Englewood
Cliffs, NJ: Prentice-Hall, Inc. ISBN 0-13-011818-4.

[St. Laurent 2000] St. Laurent, Simon. February 2000. XTech 2000
Conference Reports. ``When XML Gets Ugly''. http://www.xml.com/pub/2000
/02/xtech/megginson.html.

[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. http://www.mediacity.com/~norm/CapTheory/
ProtInf. Summarized in [Pfleeger 1997, 286].

Schneider, Fred B. 2000. "Open Source in Security: Visting the
Bizarre." Proceedings of the 2000 IEEE Symposium on Security and
Privacy (the ``Oakland Conference''), May 14-17, 2000, Berkeley, CA.
Los Alamitos, CA: IEEE Computer Society. pp.126-127.

[Schneier 1996] Schneier, Bruce. 1996. Applied Cryptography, Second
Edition: Protocols, Algorithms, and Source Code in C. New York: John
Wiley and Sons. ISBN 0-471-12845-7.

[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. http://www.counterpane.com/pptp.html.

[Schneier 1999] Schneier, Bruce. September 15, 1999. ``Open Source and
Security''. Crypto-Gram. Counterpane Internet Security, Inc. http://
www.counterpane.com/crypto-gram-9909.html

[Seifried 1999] Seifried, Kurt. October 9, 1999. Linux Administrator's
Security Guide. http://www.securityportal.com/lasg.

[Seifried 2001] Seifried, Kurt. September 2, 2001. WWW Authentication 
http://www.seifried.org/security/www-auth/index.html.

[Shankland 2000] Shankland, Stephen. ``Linux poses increasing threat to
Windows 2000''. CNET. http://news.cnet.com/news/0-1003-200-1549312.html

[Shostack 1999] Shostack, Adam. June 1, 1999. Security Code Review
Guidelines. http://www.homeport.org/~adam/review.html.

[Sibert 1996] Sibert, W. Olin. Malicious Data and Computer Security.
(NIST) NISSC '96. http://www.fish.com/security/maldata.html 

[Sitaker 1999] Sitaker, Kragen. Feb 26, 1999. How to Find Security
Holes http://www.pobox.com/~kragen/security-holes.html and http://
www.dnaco.net/~kragen/security-holes.html

[SSE-CMM 1999] SSE-CMM Project. April 1999. Systems Security
Engineering Capability Maturity Model (SSE CMM) Model Description
Document. Version 2.0. http://www.sse-cmm.org

[Stallings 1996] Stallings, William. Practical Cryptography for Data
Internetworks. Los Alamitos, CA: IEEE Computer Society Press. ISBN
0-8186-7140-8.

[Stein 1999]. Stein, Lincoln D. September 13, 1999. The World Wide Web
Security FAQ. Version 2.0.1 http://www.w3.org/Security/Faq/
www-security-faq.html

[Swan 2001] Swan, Daniel. January 6, 2001. comp.os.linux.security FAQ.
Version 1.0. http://www.linuxsecurity.com/docs/colsfaq.html.

[Swanson 1996] Swanson, Marianne, and Barbara Guttman. September 1996.
Generally Accepted Principles and Practices for Securing Information
Technology Systems. NIST Computer Security Special Publication (SP)
800-14. http://csrc.nist.gov/publications/nistpubs/index.html.

[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. http://www.oreilly.com/catalog/opensources
/book/linus.html

[TruSecure 2001] TruSecure. August 2001. Open Source Security: A Look
at the Security Benefits of Source Code Access. http://
www.trusecure.com/html/tspub/whitepapers/open_source_security5.pdf

[Unknown] SETUID(7) http://www.homeport.org/~adam/setuid.7.html.

[Van Biesbrouck 1996] Van Biesbrouck, Michael. April 19, 1996. http://
www.csclub.uwaterloo.ca/u/mlvanbie/cgisec.

[van Oorschot 1994] van Oorschot, P. and M. Wiener. November 1994.
``Parallel Collision Search with Applications to Hash Functions and
Discrete Logarithms.'' Proceedings of ACM Conference on Computer and
Communications Security.

[Venema 1996] Venema, Wietse. 1996. Murphy's law and computer security.
http://www.fish.com/security/murphy.html

[Watters 1996] Watters, Arron, Guido van Rossum, James C. Ahlstrom.
1996. Internet Programming with Python. NY, NY: Henry Hold and Company,
Inc.

[Witten 2001] September/October 2001. Witten, Brian, Carl Landwehr, and
Michael Caloyannides. ``Does Open Source Improve System Security?''
IEEE Software. pp. 57-61. http://www.computer.org/software 

[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. http://www.nic.com/~dave/
SecurityAdminGuide/index.html

[Yoder 1998] Yoder, Joseph and Jeffrey Barcalow. 1998. Architectural
Patterns for Enabling Application Security. PLoP '97 http://
st-www.cs.uiuc.edu/~hanmer/PLoP-97/Proceedings/yoder.pdf

[Zalewski 2001] Zalewski, Michael. May 16-17, 2001. Delivering Signals
for Fun and Profit: Understanding, exploiting and preventing
signal-handling related vulnerabilities. Bindview Corporation. http://
razor.bindview.com/publish/papers/signals.txt

[Zoebelein 1999] Zoebelein, Hans U. April 1999. The Internet Operating
System Counter. http://www.leb.net/hzo/ioscount.

【訳註 IPA のセキュア・プログラミング講座 <http://www.ipa.go.jp/
security/awareness/vendor/programming/index.html> も役に立ちます】

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

Appendix A. 履歴

このドキュメントを書くに当たって、いくつか主な出来事を最近のものから記
載しました。

2001-01-01 David A. Wheeler
   
    バージョン 2.70。重要な題材をたくさん追加しました。たとえば、サイト
    にまたがった悪意あるコンテンツや HTML や URI のフィルタリング、テン
    ポラリファイルの扱い等を大幅に議論を展開させました。
   
2000-05-24 David A. Wheeler
   
    ライセンスを GNU の GFDL に変更しました。内容を増やしました。
   
2000-04-21 David A. Wheeler
   
    バージョン 2.00。2000 年 4 月 21 日にドキュメントの記述形式を
    Linuxdoc DTD から the DocBook DTD に変更しました。変更に当たって援
    助してくれた Jorge Godoy 氏に感謝します。
   
2000-04-04 David A. Wheeler
   
    バージョン 1.60。 Linux と Unix の両方をカバーするように変更。ガイ
    ドラインの大部分は両者をカバーしています。開発者はアプリケーション
    を両者で動かすことを望んでいる場合が多く、両方をカバーするのは正し
    いことです。
   
2000-02-09 David A. Wheeler
   
    ドキュメントが Linux Documentation Project (LDP)に入りました。
   
1999-11-29 David A. Wheeler
   
    初期バージョン完成。公開リリース。
   
変更点の詳細はオンラインで「ChangeLog」ファイルが利用できます。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

Appendix B. おことわり

                                    鉄は鉄をもって研磨する。人はその友 
                                    によって研磨される。               
                                                                       
                                           旧約聖書箴言 27 章 17節(NIV)

電子メールで間違いを指摘してくれたり、カバーする範囲にアドバイスをして
くれたり、質問をくれたりして、私をはげましてくれた下記の皆さんに感謝し
ています。電子メールのアドレスには「thanks」を前につけてあります。そう
すれば、多量にメールを発進するメーラーが簡単にはアドレスを取得できない
からです。多量の迷惑メールをこのリストに含まれる方々に送りつける権限は
、誰にもありません。

 ・ Neil Brown (thanks.neilb@cse.unsw.edu.au)
   
 ・ Martin Douda (thanks.mad@students.zcu.cz)
   
 ・ Jorge Godoy
   
 ・ Scott Ingram (thanks.scott@silver.jhuapl.edu)
   
 ・ Michael Kerrisk
   
 ・ Doug Kilpatrick
   
 ・ John Levon (moz@compsoc.man.ac.uk)
   
 ・ Ryan McCabe (thanks.odin@numb.org)
   
 ・ Paul Millar (thanks.paulm@astro.gla.ac.uk)
   
 ・ Chuck Phillips (thanks.cdp@peakpeak.com)
   
 ・ Martin Pool (thanks.mbp@humbug.org.au)
   
 ・ Eric S. Raymond (thanks.esr@snark.thyrsus.com)
   
 ・ Marc Welz
   
 ・ Eric Werme (thanks.werme@alpha.zk3.dec.com)
   
 

このリストに載せて欲しい方は、建設的な意見を dwheeler@dwheeler.com
<mailto:dwheeler@dwheeler.com> まで送ってください。建設的な意見を送って
も謝辞を載せて欲しくない方は、意見やコメント、批判を寄せていただいた時
にお知らせください。普通、皆さんは賞賛されることを望んでいると思ってい
ますので、感謝の気持ちを表わしたいと思っています。現状は、貢献者の方々
の名前をドキュメントのこのリストに追加して、コメントのさらに詳しい説明
については、ChangeLog(オンラインで利用できます)に書いて置きます。アイデ
ィアを送ってくれたのは彼らですが、実際テキストに起したのは私自身です。
何か間違いがあったとしても、彼らを責めないでください。そうするかわりに
、別に建設的な意見を私に贈っていただければ、と思います。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

Appendix C. ドキュメントのライセンスについて

                                    この勅書の写しは各州で国の定めとし 
                                    て全国民に公示され、人々はその日に 
                                    備えた。                           
                                                                       
                                     旧約聖書エステル記 3 章 14 節(NIV)

このドキュメントは David A. Wheeler が著作権を保持しています (Copyright
(C) 1999-2000 David A. Wheeler)。 GNU General Public License (GPL) にも
とづき、複製と再配布および修正を許可しています。バージョン 1.1 以上は、
Free Software Foundation で出版してしています。変更不可部分は「著者につ
いて」で、表紙と裏表紙のテキストはありません。ライセンスのコピーは下記
の Appendix D にあります。

これらの条件では他の Web サイトがミラーしても良いことになっていますが、
下記の条件に必ず従ってください。

 ・ マスターのサイトから自動的にミラーが更新されること。
   
 ・ マスターのサイトの場所(http://www.dwheeler.com/secure-programs) を
    ハイパーテキストのリンク形式で明示すること。
   
 ・ 私(David A. Wheeler)へ著者に対する感謝の意を表わすこと。
   
 

最初の 2 点は主に、繰り返し昔あった間違いを聞かれるのを防ぐためです。 1
年も前に修正した間違いについて聞かれるのは困り物です。ドキュメント正し
くミラーしていないからといった理由で。マスターのサイトにリンクを張れば
、ユーザはミラーが最新かどうかを確認できます。私は強固なセキュリティを
必要としているサイトの問題に過敏なので、インターネットに普通に接続する
危険を犯せません。同じような状況ならば、他の妥協点を見つけるようにして
ください。そして時には媒体を運んで、環境を更新してください。

このライセンスではドキュメントは修正可能です。しかし書いたものはあなた
のもの (つまり盗用)とは主張できません。修正したバージョンがオリジナルの
作品と同じであると主張もできません。作品を修正しても、作品すべての著作
権は移動しません。これは著作権関連の法律がいう「パブリック・ドメイン」
な作品ではありません。ライセンスについての詳細は Appendix D を参照して
ください。ライセンスが何を許しているか疑問があるなら、私に連絡してくだ
さい。あなたが行った変更をとりまとめの元締め(現在は David A. Wheeler
氏)に送れば、たいていその変更は他の変更とともに原本に反映されます。

とは言ったものの、私は法律家ではありません。著作権の法律では、作品の構
成要素として問題にならない程小さいものに対しては、著作権を認めていない
、というのが私の著者としての立場です(たとえば、「私は B フラットと B フ
ラット・マイナーのコードの権利をすべて持っている」)。本物のプログラムと
比較すると、取るに足らない言葉の断片は、わずかな大きさという意味では同
じです。私はこれまで、他の人が書いたコードには、それが小さくともを感謝
を表することに努めてきました。それでも皆さんの中には、このコードの法的
な位置づけが気になるなる方もいらっしゃると思います。そこで、皆さんがこ
のコードを皆さんのソフトウェアで利用できることをはっきりさせたいと思い
ます。したがって、このドキュメントに直接書かれているコードの些細な断片
は、「MIT ライセンス」の元でリリースします。法的に恐れるほどの制約がな
いことを保証します。

  Source code in this book not otherwise identified is                 
  Copyright (c) 1999-2001 David A. Wheeler.                            
                                                                       
  Permission is hereby granted, free of charge, to any person          
  obtaining a copy of the source code in this book not                 
  otherwise identified (the "Software"), to deal in the                
  Software without restriction, including without limitation           
  the rights to use, copy, modify, merge, publish, distribute,         
  sublicense, and/or sell copies of the Software, and to               
  permit persons to whom the Software is furnished to do so,           
  subject to the following conditions:                                 
                                                                       
  The above copyright notice and this permission notice shall be       
  included in all copies or substantial portions of the Software.      
                                                                       
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,      
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE                 
  WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR              
  PURPOSE AND NONINFRINGEMENT.                                         
  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE                
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,                    
  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,                 
  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE              
  OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                        
【訳註：各種オープンソース系のライセンスは、                           
http://www.opensource.org                                              
 が参考になります。OSG-JP <http://www.opensource.jp>                   
 もありますが、まだ MIT ライセンスは翻訳されていません】               

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

Appendix D. GNU Free Documentation License

Version 1.1, March 2000

Copyright 2000

      Free Software Foundation, Inc. 
      59 Temple Place, Suite 330, 
      Boston, 
      MA  
      02111-1307  
      USA
    

Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.

0. PREAMBLE
   
    The purpose of this License is to make a manual, textbook, or other
    written document "free" in the sense of freedom: to assure everyone
    the effective freedom to copy and redistribute it, with or without
    modifying it, either commercially or noncommercially. Secondarily,
    this License preserves for the author and publisher a way to get
    credit for their work, while not being considered responsible for
    modifications made by others.
   
    This License is a kind of "copyleft", which means that derivative
    works of the document must themselves be free in the same sense. It
    complements the GNU General Public License, which is a copyleft
    license designed for free software.
   
    We have designed this License in order to use it for manuals for
    free software, because free software needs free documentation: a
    free program should come with manuals providing the same freedoms
    that the software does. But this License is not limited to software
    manuals; it can be used for any textual work, regardless of subject
    matter or whether it is published as a printed book. We recommend
    this License principally for works whose purpose is instruction or
    reference.
   
1. APPLICABILITY AND DEFINITIONS
   
    This License applies to any manual or other work that contains a
    notice placed by the copyright holder saying it can be distributed
    under the terms of this License. The "Document" , below, refers to
    any such manual or work. Any member of the public is a licensee,
    and is addressed as "you".
   
    A "Modified Version" of the Document means any work containing the
    Document or a portion of it, either copied verbatim, or with
    modifications and/or translated into another language.
   
    A "Secondary Section" is a named appendix or a front-matter section
    of the Document that deals exclusively with the relationship of the
    publishers or authors of the Document to the Document's overall
    subject (or to related matters) and contains nothing that could
    fall directly within that overall subject. (For example, if the 
    Document is in part a textbook of mathematics, a Secondary Section
    may not explain any mathematics.) The relationship could be a
    matter of historical connection with the subject or with related
    matters, or of legal, commercial, philosophical, ethical or
    political position regarding them.
   
    The "Invariant Sections" are certain Secondary Sections whose
    titles are designated, as being those of Invariant Sections, in the
    notice that says that the Document is released under this License.
   
    The "Cover Texts" are certain short passages of text that are
    listed, as Front-Cover Texts or Back-Cover Texts, in the notice
    that says that the Document is released under this License.
   
    A "Transparent" copy of the Document means a machine-readable copy,
    represented in a format whose specification is available to the
    general public, whose contents can be viewed and edited directly
    and straightforwardly with generic text editors or (for images
    composed of pixels) generic paint programs or (for drawings) some
    widely available drawing editor, and that is suitable for input to
    text formatters or for automatic translation to a variety of
    formats suitable for input to text formatters. A copy made in an
    otherwise Transparent file format whose markup has been designed to
    thwart or discourage subsequent modification by readers is not 
    Transparent. A copy that is not "Transparent" is called "Opaque".
   
    Examples of suitable formats for Transparent copies include plain
    ASCII without markup, Texinfo input format, LaTeX input format,
    SGML or XML using a publicly available DTD, and standard-conforming
    simple HTML designed for human modification. Opaque formats include
    PostScript, PDF, proprietary formats that can be read and edited
    only by proprietary word processors, SGML or XML for which the DTD
    and/or processing tools are not generally available, and the
    machine-generated HTML produced by some word processors for output
    purposes only.
   
    The "Title Page" means, for a printed book, the title page itself,
    plus such following pages as are needed to hold, legibly, the
    material this License requires to appear in the title page. For
    works in formats which do not have any title page as such, "Title
    Page" means the text near the most prominent appearance of the
    work's title, preceding the beginning of the body of the text.
   
2. VERBATIM COPYING
   
    You may copy and distribute the Document in any medium, either
    commercially or noncommercially, provided that this License, the
    copyright notices, and the license notice saying this License
    applies to the Document are reproduced in all copies, and that you
    add no other conditions whatsoever to those of this License. You
    may not use technical measures to obstruct or control the reading
    or further copying of the copies you make or distribute. However,
    you may accept compensation in exchange for copies. If you
    distribute a large enough number of copies you must also follow the
    conditions in section 3.
   
    You may also lend copies, under the same conditions stated above,
    and you may publicly display copies.
   
3. COPYING IN QUANTITY
   
    If you publish printed copies of the Document numbering more than
    100, and the Document's license notice requires Cover Texts, you
    must enclose the copies in covers that carry, clearly and legibly,
    all these Cover Texts: Front-Cover Texts on the front cover, and
    Back-Cover Texts on the back cover. Both covers must also clearly
    and legibly identify you as the publisher of these copies. The
    front cover must present the full title with all words of the title
    equally prominent and visible. You may add other material on the
    covers in addition. Copying with changes limited to the covers, as
    long as they preserve the title of the Document and satisfy these
    conditions, can be treated as verbatim copying in other respects.
   
    If the required texts for either cover are too voluminous to fit
    legibly, you should put the first ones listed (as many as fit
    reasonably) on the actual cover, and continue the rest onto
    adjacent pages.
   
    If you publish or distribute Opaque copies of the Document
    numbering more than 100, you must either include a machine-readable
    Transparent copy along with each Opaque copy, or state in or with
    each Opaque copy a publicly-accessible computer-network location
    containing a complete Transparent copy of the Document, free of
    added material, which the general network-using public has access
    to download anonymously at no charge using public-standard network
    protocols. If you use the latter option, you must take reasonably
    prudent steps, when you begin distribution of Opaque copies in
    quantity, to ensure that this Transparent copy will remain thus
    accessible at the stated location until at least one year after the
    last time you distribute an Opaque copy (directly or through your
    agents or retailers) of that edition to the public.
   
    It is requested, but not required, that you contact the authors of
    the Document well before redistributing any large number of copies,
    to give them a chance to provide you with an updated version of the
    Document.
   
4. MODIFICATIONS
   
    You may copy and distribute a Modified Version of the Document
    under the conditions of sections 2 and 3 above, provided that you
    release the Modified Version under precisely this License, with the
    Modified Version filling the role of the Document, thus licensing
    distribution and modification of the Modified Version to whoever
    possesses a copy of it. In addition, you must do these things in
    the Modified Version:
   
     A. Use in the Title Page (and on the covers, if any) a title
        distinct from that of the Document, and from those of previous
        versions (which should, if there were any, be listed in the
        History section of the Document). You may use the same title as
        a previous version if the original publisher of that version
        gives permission.
       
     B. List on the Title Page, as authors, one or more persons or
        entities responsible for authorship of the modifications in the
        Modified Version, together with at least five of the principal
        authors of the Document (all of its principal authors, if it
        has less than five).
       
     C. State on the Title Page the name of the publisher of the 
        Modified Version, as the publisher.
       
     D. Preserve all the copyright notices of the Document.
       
     E. Add an appropriate copyright notice for your modifications
        adjacent to the other copyright notices.
       
     F. Include, immediately after the copyright notices, a license
        notice giving the public permission to use the Modified Version
        under the terms of this License, in the form shown in the
        Addendum below.
       
     G. Preserve in that license notice the full lists of Invariant
        Sections and required Cover Texts given in the Document's
        license notice.
       
     H. Include an unaltered copy of this License.
       
     I. Preserve the section entitled "History", and its title, and add
        to it an item stating at least the title, year, new authors,
        and publisher of the Modified Version as given on the Title
        Page. If there is no section entitled "History" in the Document
        , create one stating the title, year, authors, and publisher of
        the Document as given on its Title Page, then add an item
        describing the Modified Version as stated in the previous
        sentence.
       
     J. Preserve the network location, if any, given in the Document
        for public access to a Transparent copy of the Document, and
        likewise the network locations given in the Document for
        previous versions it was based on. These may be placed in the
        "History" section. You may omit a network location for a work
        that was published at least four years before the Document
        itself, or if the original publisher of the version it refers
        to gives permission.
       
     K. In any section entitled "Acknowledgements" or "Dedications",
        preserve the section's title, and preserve in the section all
        the substance and tone of each of the contributor
        acknowledgements and/or dedications given therein.
       
     L. Preserve all the Invariant Sections of the Document, unaltered
        in their text and in their titles. Section numbers or the
        equivalent are not considered part of the section titles.
       
     M. Delete any section entitled "Endorsements". Such a section may
        not be included in the Modified Version.
       
     N. Do not retitle any existing section as "Endorsements" or to
        conflict in title with any Invariant Section.
       
    If the Modified Version includes new front-matter sections or
    appendices that qualify as Secondary Sections and contain no
    material copied from the Document, you may at your option designate
    some or all of these sections as invariant. To do this, add their
    titles to the list of Invariant Sections in the Modified Version's
    license notice. These titles must be distinct from any other
    section titles.
   
    You may add a section entitled "Endorsements", provided it contains
    nothing but endorsements of your Modified Version by various
    parties--for example, statements of peer review or that the text
    has been approved by an organization as the authoritative
    definition of a standard.
   
    You may add a passage of up to five words as a Front-Cover Text,
    and a passage of up to 25 words as a Back-Cover Text, to the end of
    the list of Cover Texts in the Modified Version. Only one passage
    of Front-Cover Text and one of Back-Cover Text may be added by (or
    through arrangements made by) any one entity. If the Document
    already includes a cover text for the same cover, previously added
    by you or by arrangement made by the same entity you are acting on
    behalf of, you may not add another; but you may replace the old
    one, on explicit permission from the previous publisher that added
    the old one.
   
    The author(s) and publisher(s) of the Document do not by this
    License give permission to use their names for publicity for or to
    assert or imply endorsement of any Modified Version .
   
5. COMBINING DOCUMENTS
   
    You may combine the Document with other documents released under
    this License, under the terms defined in section 4 above for
    modified versions, provided that you include in the combination all
    of the Invariant Sections of all of the original documents,
    unmodified, and list them all as Invariant Sections of your
    combined work in its license notice.
   
    The combined work need only contain one copy of this License, and
    multiple identical Invariant Sections may be replaced with a single
    copy. If there are multiple Invariant Sections with the same name
    but different contents, make the title of each such section unique
    by adding at the end of it, in parentheses, the name of the
    original author or publisher of that section if known, or else a
    unique number. Make the same adjustment to the section titles in
    the list of Invariant Sections in the license notice of the
    combined work.
   
    In the combination, you must combine any sections entitled
    "History" in the various original documents, forming one section
    entitled "History"; likewise combine any sections entitled
    "Acknowledgements", and any sections entitled "Dedications". You
    must delete all sections entitled "Endorsements."
   
6. COLLECTIONS OF DOCUMENTS
   
    You may make a collection consisting of the Document and other
    documents released under this License, and replace the individual
    copies of this License in the various documents with a single copy
    that is included in the collection, provided that you follow the
    rules of this License for verbatim copying of each of the documents
    in all other respects.
   
    You may extract a single document from such a collection, and
    distribute it individually under this License, provided you insert
    a copy of this License into the extracted document, and follow this
    License in all other respects regarding verbatim copying of that
    document.
   
7. AGGREGATION WITH INDEPENDENT WORKS
   
    A compilation of the Document or its derivatives with other
    separate and independent documents or works, in or on a volume of a
    storage or distribution medium, does not as a whole count as a 
    Modified Version of the Document, provided no compilation copyright
    is claimed for the compilation. Such a compilation is called an
    "aggregate", and this License does not apply to the other
    self-contained works thus compiled with the Document , on account
    of their being thus compiled, if they are not themselves derivative
    works of the Document. If the Cover Text requirement of section 3
    is applicable to these copies of the Document, then if the Document
    is less than one quarter of the entire aggregate, the Document's 
    Cover Texts may be placed on covers that surround only the Document
    within the aggregate. Otherwise they must appear on covers around
    the whole aggregate.
   
8. TRANSLATION
   
    Translation is considered a kind of modification, so you may
    distribute translations of the Document under the terms of section
    4. Replacing Invariant Sections with translations requires special
    permission from their copyright holders, but you may include
    translations of some or all Invariant Sections in addition to the
    original versions of these Invariant Sections. You may include a
    translation of this License provided that you also include the
    original English version of this License. In case of a disagreement
    between the translation and the original English version of this
    License, the original English version will prevail.
   
9. TERMINATION
   
    You may not copy, modify, sublicense, or distribute the Document
    except as expressly provided for under this License. Any other
    attempt to copy, modify, sublicense or distribute the Document is
    void, and will automatically terminate your rights under this
    License. However, parties who have received copies, or rights, from
    you under this License will not have their licenses terminated so
    long as such parties remain in full compliance.
   
10. FUTURE REVISIONS OF THIS LICENSE
   
    The Free Software Foundation <http://www.gnu.org/fsf/fsf.html> may
    publish new, revised versions of the GNU Free Documentation License
    from time to time. Such new versions will be similar in spirit to
    the present version, but may differ in detail to address new
    problems or concerns. See http://www.gnu.org/copyleft/ <http://
    www.gnu.org/copyleft>.
   
    Each version of the License is given a distinguishing version
    number. If the Document specifies that a particular numbered
    version of this License "or any later version" applies to it, you
    have the option of following the terms and conditions either of
    that specified version or of any later version that has been
    published (not as a draft) by the Free Software Foundation. If the 
    Document does not specify a version number of this License, you may
    choose any version ever published (not as a draft) by the Free
    Software Foundation.
   
Addendum
   
    To use this License in a document you have written, include a copy
    of the License in the document and put the following copyright and
    license notices just after the title page:
   
    Copyright YEAR YOUR NAME.
   
    Permission is granted to copy, distribute and/or modify this
    document under the terms of the GNU Free Documentation License,
    Version 1.1 or any later version published by the Free Software
    Foundation; with the Invariant Sections being LIST THEIR TITLES,
    with the Front-Cover Texts being LIST, and with the Back-Cover
    Texts being LIST. A copy of the license is included in the section
    entitled "GNU Free Documentation License".
   
    If you have no Invariant Sections, write "with no Invariant
    Sections" instead of saying which ones are invariant. If you have
    no Front-Cover Texts, write "no Front-Cover Texts" instead of
    "Front-Cover Texts being LIST"; likewise for Back-Cover Texts.
   
    If your document contains nontrivial examples of program code, we
    recommend releasing these examples in parallel under your choice of
    free software license, such as the GNU General Public License
    <http://www.gnu.org/copyleft/gpl.html>, to permit their use in free
    software.
   
    【訳註：日本語訳については、OSG-JP にある GNU FDL (フリー文書利用許
    諾契約書) 日本語訳 <http://www.opensource.jp/fdl/fdl.ja.txt>を参考
    にしてください】
   
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

Appendix E. About the Author

David A. Wheeler is an expert in computer security and has long
specialized in development techniques for large and high-risk software
systems. He has been involved in software development since the
mid-1970s, and been involved with Unix and computer security since the
early 1980s. His areas of knowledge include computer security, software
safety, vulnerability analysis, inspections, Internet technologies,
software-related standards (including POSIX), real-time software
development techniques, and numerous computer languages (including Ada,
C, C++, Perl, Python, and Java).

Mr. Wheeler is co-author and lead editor of the IEEE book Software
Inspection: An Industry Best Practice, author of the book Ada95: The
Lovelace Tutorial, and co-author of the GNOME User's Guide. He is also
the author of many smaller papers and articles, including the Linux 
Program Library HOWTO.

Mr. Wheeler hopes that, by making this document available, other
developers will make their software more secure. You can reach him by
email at dwheeler@dwheeler.com (no spam please), and you can also see
his web site at http://www.dwheeler.com. 【訳註：この「About the Author
」は GNU FDL が定める「変更不可部分 (Invariant Sections)」に指定してあ
るので、原文をそのまま掲載します】

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 

Appendix F. 日本語版謝辞

翻訳を行うに当たって、下記の方々にお世話になりました。この場をかりてお
礼申し上げます。ありがとう、皆さん！

 ・ 野首貴嗣さん
   
 ・ えだゆきひこさん
   
 ・ 小川英範さん
   
 ・ 武井伸光さん
   
 ・ 小林雅典さん
   
 ・ 川崎貴彦さん
   
 ・ 山下義之さん
   
 ・ 宮川寧夫さん
   
Notes

[1] 技術的にはハイパーテキストのリンクは、「uniform resource identifier
    」(URI) といえます。「Uniform Resource Locator」(URL)は、URI のサブ
    セットとして使われ、まずアクセスする手段(たとえばネットワーク上の「
    位置」)を表示することで、リソースを特定しています。リソースの名称や
    その他の属性では特定しません。「URL」を「URI」と同じ意味で使う場合 
    が多いのですが、それは URI を実現している中で、一番使われているのが
    URL だからです。たとえば、URI で使用するエンコードのことを実際は「 
    URL エンコーディング」と呼んでいます。                             

