[ホーム] -> [Aache + PHP + PostgreSQL 実験室]

Apache のセキュリティ

ディレクトリのパーミッション

特に Apache ではなく、すべてのソフトウェアにいえることですが、ファイルシステムの権限は適切に設定する必要があります。

Apache が出力するファイルは、基本的にログファイルと、プロセスID が書かれたファイルになりますが、このファイルは、Apache を起動したユーザで作成されます。普通 root ユーザで起動されると思うので、ログファイルも root で作成されます。このログを出力するディレクトリを、必ずルートユーザ以外が書き込めないようにしておく必要があります。たとえファイルに読み書きの権限がなくても、ディレクトリに書き込み権限があると、ファイルを削除することが可能になります。

同じような理由から、コンテンツのディレクトリもきちんと設定してください。場合によってはコンテンツは複数の人で作業することもあるかと思います。この場合でも大丈夫なようにしっかりオーナとパーミッションの設定をしましょう。複数の人で管理する場合、ディレクトリにのグループにステッキービットをセットするといい場合もあります。

# mkdir www
# chown root.wwwadmin www
# chmod 2775 www
# ls -l
drwxrwsr-x    2 root     wwwadmin     4096 May 25 15:23 www

グループにステッキービットをセットしておくと、そのディレクトリに誰がファイルやディレクトリを作っても、グループオーナはディレクトリのグループオーナと同じになります。このグループはしっかりと管理してください。

デフォルトのアクセス制御

設定が複雑になったり、勘違いをしてたりすると、気付かないうちにいろいろなファイルにアクセス出来るようになっていたりします。とりあえず、被害を最小限にするために、httpd.conf で、ルートディレクトリのアクセスを禁止しておきましょう。

<Directory />
  Order Deny,Allow
  Deny from all
</Directory>

そして、許可したいディレクトリにだけ、アクセスを許可します。また、シンボリックリンクも利用できないようにしておくといいでしょう。

<Directory />
  Options None
  Order Deny,Allow
  Deny from all
</Directory>

ただ、シンボリックリンクは何かと便利です。その場合は、シンボリックリンクファイルがあるディレクトリに対してのみ、Options +SymLinksIfOwnerMatch を指定しておきます。

<Directory /var/www/html/list>
  Options +SymLinksIfOwnerMatch
</Directory>

Options +SymLinksIfOwnerMatch は、パフォーマンスを考えると、なるべく使用しない方がいい設定です。例えば上記の設定で(DocumentRoot /var/www/html)、/list/abc/xyz/last.html にアクセスした場合、/var/www/html/list/abc, /var/www/html/list/abc/xyz, /var/www/html/list/abc/xyz/last.html に対して、lstat(2) システムコールを発行します。このシステムコールは比較的コストの高い(負荷をかける)処理で、しかも Apache は lstat(2) の結果をキャッシュしないそうです(マニュアルによる)。従って、アクセスすべてに対して、lstat(2) が発行されるので、この範囲を最小限に抑えるように設定するように心がけましょう。

また、マニュアルによると、UserDir ディレクティブで、root ユーザを指定するように推奨されています。これは、誤って root のホームディレクトリに public_html と言うなのシンボリックリンクファイルを作られると危険だからです。このシンボリックリンクの参照先が、ルートディレクトリだったとしたら、Options SymLinksIfOwnerMatch だとしてもすべてのファイルにアクセスできるようになってしまいます。

UserDir disable root

気を付けないと危険な機能

CGI や SSI は、便利ですが、無制限に利用できるようにすると非常に危険です。絶対自分しか利用しないならいいのですが、不特定多数の人に利用してもらうときは、ある程度制限を設けた方が賢明です。

まず、SSI ですが、Options Includes ではなく、Options IncludesNOEXEC にしておきましょう。これだけでもかなり違います。また、SSI で利用可能な拡張子を決めましょう。便利だからと言って、拡張子 .html に対して SSI を許可してしまうのは考え物です。SSI ではない普通の HTML ファイルも SSI ハンドラに渡してしまうので、思わぬトラブルの原因になったり、パフォーマンスにも影響します。当然、SSI を実行できるディレクトリも制限するべきです。

<Directory /var/www/html/ssi>
  Options +IncludesNOEXEC
  AddHandler server-parsed                               .shtml
  AddType    "text/x-server-parsed-html; charset=EUC-JP" .shtml
</Directory>

CGI は何でも出来る反面、その実行権限と内容には十分注意を払うべきです。実行権限は、普通 Apache の User ディレクティブで指定したユーザになります。仮想ホストなどを使っている場合は、仮想ホスト毎に User ディレクティブを指定できるので、仮想ホスト毎に責任者が違う場合は、実行ユーザを分けてみるのいいかもしれません。

また、suexec の機能を使うことも出来ます。Apache コンパイルするときに、--enable-suexec オプションを付けて実行すると、suexec というコマンドがインストールされます。

> ./configure --enable-module=most \
              --enable-shared=max \
              --enable-suexec \
              --suexec-caller=www \
              --suexec-docroot=/var/www/html \
              --suexec-userdir=public_html \
              --suexec-uidmin=100 \
              --suexec-gidmin=100

--suexec-caller は、httpd.confUser ディレクティブで指定する予定のユーザを指定してください。ここで指定したユーザと、実際の Apache の実行時ユーザが違うと、suexec は動作しません(これにより一般ユーザが直接 suexec を実行できないようになっている)。もっと細かい制御を行いたい場合(ユーザのディレクトリが特殊だとか)は、src/support/suexec.c を直接修正しないといけません。C 言語が分かる人であれば対して苦労なく修正できると思いますが・・・。

CGI の内容をチェックするのはとても面倒で、ソースに目を通して危険なことをしていないかチェックする必要があります。意図しないファイルの上書きや削除といったことは、suexec を利用すれば、被害はそのユーザだけに限定されます。しかし、意図しない読み込みは、UNIX が大抵のファイルを誰でも読めることを考えると防ぐのは難しいです(/etc/passwd とか)。

ここまで心配するようだと、CGI を実行させないようにするか、chroot の併用も考慮に入れる必要があります。CGI が C 言語などであればスタティックにリンクしておけば実行できますが、Perl などのインタプリタ系はちょっと面倒ですね。案としては、suexec を改造し、Perl をオープンしてから chroot コールしてから CGI を読み込み、オープン済みの Perl に渡す、ようにすればいいかなとか。でも use, require なんかは困りますねぇ。いや、内部関数でもファイルを読みに行ってるか・・・。うーむ。

SSL の利用

Apache 自体のセキュリティではありませんが、やはり Web サイトを構築するには、SSL の利用も考えに入れないといけません。ここで、Apache で SSL を利用する方法を説明したいと思います(とは言っても、私自身正式なサーバ証明書は持ったこと無いのですが)。

必要なソフトが二つあります。OpenSSL と、mod_ssl です。それぞれのインストールを説明してあるので、試してみてください。

サーバ証明書を作るときは、Common Name(Common Name (eg, your name or your server's hostname) []: という質問)に、正しい Web サーバ名を指定しないといけません。例えば、https://www.domain.com/ という URL を使いたい場合は、www.domain.com と指定します。これが違っていると、証明書を利用したときに、クライアント(ブラウザ)が警告を発します(サーバ名と証明書の名前が違うため)。

まずは、mod_ssl の設定を行わなければなりません。「OpenSSL のインストール」の説明で、サーバ証明書と、秘密鍵ファイルを作成したと思いますが、そのファイルのパスを httpd.conf に記述しないといけません。それぞれ SSLCertificateFile, SSLCertificateKeyFile がそれに当たります。httpd.conf の中にすでに該当場所があるので、そこを修正してみて下さい。

# サーバ証明書
SSLCertificateFile  conf/ssl.crt/server.crt
# 秘密鍵ファイル
SSLCertificateFile  conf/ssl.key/server.key

基本的には、設定すべき項目はこれだけです。それでは、Apache を起動してみましょう。SSL 付きで起動する場合は、apachectl startssl で起動します。

# ./apachectl startssl

起動したら、ブラウザからアクセスしてみます。https:// でアクセスしてみて、動いているかを確認します。

アクセスに成功すると、大抵のブラウザは、「サーバ証明書の署名が不明ですが、正しいサーバ証明書ですか?」などと言った趣旨の警告をしてくると思います。これはサーバ証明書を自己署名しているからです。本来、このサーバ証明書は、認証局(CA とか呼ばれる)に署名してもらわないといけないものです。

自己署名のサーバ証明書を使っても、サーバとクライアント間の通信は暗号化されます。しかし、自己署名だと、クライアントから見て、サーバが本物かどうかは確認できません。そのためブラウザは警告を発するのです。

例えば、誰かが全く同じ内容でサーバ証明書を作成し、それに自己署名したとしましょう。この場合、本来正しいサーバ証明書と、誰かが作った証明書のどちらが正しい証明書かは、利用する人からは判断できません。これを防ぐには、自分以外の人がこの証明書に署名(つまり、証明書が本物だと証明すること)しないといけません。誰でもいいわけではなく、認証局と呼ばれる機関に署名してもらいます。VeriSignThawte などがこれに当たります。認証局の署名があれば、ブラウザはそのサーバ証明書を正しいものだと認識します。認証局は、正しい手続きを経たサーバ証明書にしか署名をしないのです。

もし、SSL を利用してサービスをしたい場合は、きちんと認証局に署名をしてもらうようにしましょう。もちろん無料ではありませんが、SSL を利用するサイトとなると商用サイトでしょうから、それからの収入に比べたら微々たるものです(たぶん)。

SSL の設定変更ですが、デフォルトの httpd.conf の設定は、SSL の部分(つまり https:// でのアクセス)が、ポート 443 の仮想ホストとして設定されています(ポート 443 は https のデフォルトポート)。設定を変えたい場合は、仮想ホストの説明を読みながらトライしてみて下さい。まあ、そう大きく変更する必要もないかとは思いますが・・・。

SSL を利用する場合、大きな注意点があります。SSL での接続は、サーバに非常に負荷がかかります。特に、ユーザが最初にサーバにアクセスした瞬間です。高アクセスが予想されるサイトでは、十分負荷テストを行って下さい。普通のアクセスに比べ、100 倍以上は負荷がかかると見込んで間違いないと思います。

もし問題がありそうな場合は、SSL の暗号化をサポートする専用のハードウェアがあります。PCI バスとかに挿して SSL の暗号化を専用に処理するチップや、ルータのような専用機械でネットワークと Web サーバの間につなぎ SSL を処理する(Web サーバと専用機の間は普通の HTTP だが、専用機とクライアント間は SSL となる)ものなどいろいろあります。ロードバランサで負荷分散している場合は、SSL セッションを持続させる必要があるので、ロードバランサ自体に SSL をサポートするオプションがあるはずです。

ホームへ