Apache Proxy のディレクティブ (mod_proxy) を使って LAMP セキュリティーを改善する

複数のユーザー ID を持つ仮想ホスティングが可能に

この記事では Nick Maynard が、Apache の mod_proxy モジュールを使って LAMP セットアップのセキュリティーを改善する方法の概要を説明します。この記事は Linux のみを対象としますが、ここで説明する原則のいくつかは、他のオペレーティング・システムにも適用することができます。

Nick Maynard, Scenario Analyst, IBM

Author photoNick Maynard は、2003 年に Imperial College of Science, Technology, and Medicine を卒業後、IBM UK Ltd. に入社して以来、IBM Hursley の Scenario Analysis Lab で働いています。専門分野は Linux や Web サービス、ビジネス統合技術などです。



2006年 11月 29日

Apache Software Foundation の HTTP サーバー・プロジェクト (一般には Apache として知られています) は、今日のインターネットで 60% 以上のマーケット・シェアを誇る、支配的な Web サーバーです。Apache サーバーは徐々に、LAMP として知られる構成のフリー・ソフトウェア・プログラムの一部となりつつあります (LAMP は、Linux®、Apache、MySQL、そして PHP というオープンソース技術の上に構築される Web プラットフォームです)。この記事では、mod_proxy モジュールと複数のバックエンド・サーバーを使うことによって、LAMP インストールのセキュリティーを改善する方法を探ります。そして、この方法の利点と欠点についても触れ、また実際に動作する構成の例についても説明します。

PHP と Apache、セキュリティーの難問

LAMP 管理者にとって難問の 1 つは、フル・インストールした PHP の全機能を提供する一方で、システムの全ユーザーにセキュアな環境を保証しなければならないことです。そのために PHP のセーフ・モードを使う方法もありますが、そうするとユーザーに必要以上に制限をかけてしまうことになり、また一部の PHP アプリケーションは、この機能を有効にすると動作しなくなってしまいます。

PHP のセキュリティー問題の根源は、大部分の Apache サーバーの構成方法そのものにあります。大部分の Apache インストールは特別な www-data ユーザー ID で実行するため、Web サイトをホストするすべてのユーザーは、この ID のユーザーが Web サイトでホストされるファイルを読み取れるように、デフォルトで保証しなければなりません。つまり、あるユーザーの Web アクセス可能ファイルすべてに対して、システム上の他の全ユーザーからアクセスできることになります。従ってそうしたファイルが、ファイルの読み取りを保証する必要がなければ関係なかったシステム上のセキュリティーの問題によって、攻撃の対象となりうるのです。この問題は、ファイルやディレクトリーがその www-data ユーザーによって書き込み可能なものとして設定される場合には、一層深刻になります。

Perl や Python などの一般的な言語で書かれる CGI プログラムでは、suEXEC 機構を使うことによって、この問題の影響を一部回避することができます。簡単に言うと、suEXEC は特別な中間プログラムを使うことによって、そのプログラムを所有するユーザー ID として CGI プログラムを実行します。(この詳細を解説した記事を「参考文献」にあげてあります。) これは非常に効果的な機構であり、長年一般的に使われてきました。

しかし mod_php モジュールを使って PHP ページをホストする場合には、PHP ページはメインの Apache プロセスの一部として実行されます。そのため PHP ページは、Apache プロセスの持つすべての資格情報を継承します。従って PHP ページがファイルシステム上で行うすべての作業は、www-data ユーザーとして実行されなければなりません。

複数のユーザー ID で Apache を実行する

明らかなことですが、上記の問題に対するソリューションは、あるユーザーのドメインに対するすべてのリクエストを、そのユーザーの資格情報のみを持つ Apache インスタンスからホストすることです。そのために Apache を、起動時に任意のユーザーの資格情報を求めるように構成します。こうすると、インターネットから見えてしまう個々の IP アドレスとポートの組み合わせが各ユーザーに割り当てられるという単純な設定に対する問題を解決することができます。

IP アドレスが貴重な、もっと複雑な設定では、この方法ではうまくいかず、仮想ホスティングを使う他ありません。仮想ホスティングは Apache のインストールでは広く使われる手法であり、ある 1 つの Apache インスタンスによって、特定の IP アドレスとポートの組み合わせをコントロールします。これによって、複数ユーザーに属する複数ドメインを同じ IP アドレスとポートの組み合わせでホストできてしまう可能性を排除することができます。

Apache 2.0 では、MPM (multiprocessing module) の概念が導入されました。基本的な Apache 2.0 パッケージに提供されている MPM の中には、perchild という名前の実験的なモジュールがありました。このモジュールを使うと、IP アドレスとポートの組み合わせに配布スレッドを割り当て、個々のユーザーの資格情報の下で実行するサテライト・スレッドにリクエストを渡すことによって、複数のユーザー ID を使った仮想ホスティングを行うことができます。残念なことに perchild は実験のまま、幸運な人に使われただけで終わり、やがて Apache 2.2 がリリースされると、正式な Apache ディストリビューションから削除されてしまいました。しかしその前に、安定して動作する perchild 風の MPM への要求が続いていることを認識して、広範な Apache コミュニティーが、このギャップを埋めるためのいくつかの MPM への取り組みを開始しました。MetuxMPM と、MetuxMPM から分かれたプロセス指向の peruser は、この目標に向かって作業を続けています。(MetuxMPM と peruser MPM に関して詳しくは、「参考文献」を参照してください。)


mod_proxy というソリューション

複数ユーザー ID での仮想ホスティングを直接提供する正式な Apache MPM はありませんが、少しばかりインテリジェントな構成と管理を行えば、そうした動作をするApache システムを構築することは可能です。その考え方の中核にあるのが、mod_proxy モジュールを使用することです。さまざまな機能の中で、mod_proxy モジュールの最大の特徴は、Apache がページに対するリクエストを他のサーバーに転送できること、そしてそのレスポンスを、元々リクエストを発行したクライアントに戻せる点です。

リスト 1. 基本的なリクエスト転送のための、逆プロキシー構成の例
ProxyRequests Off

ProxyPass /foo http://foo.example.com/bar
ProxyPassReverse /foo http://foo.example.com/bar

リスト 1 のコードは、あるホストの /foo という階層構造の下の任意ページに対するリクエストを、ttp://foo.example.com/bar でホストされる対応ページに転送する単純な例です。例えば、/foo/index.htm というページは、http://foo.example.com/bar/index.htm に転送されます。この原理を使えば、私達の問題を解決することができます。

サンプル・シナリオ

ここで、Apache 管理者が 2 件の別々の顧客のために 2 つのドメインをホストしなければならないシナリオを考えてください。1 件の顧客は起業したばかりのオンライン・ビジネスであり、オンライン・セキュリティーを気にしています。もう 1 件はセキュリティーに無頓着な個人顧客であり、自分のサイトにセキュアではないコードをアップロードすることで知られています。Apache 管理者は、こうした要因を考慮して、2 つのサイトをお互いに分離する手段をとらなければなりません。

従って管理者は、起業したばかりのオンライン・ビジネス (ユーザー ID は startup) が所有する www.startup.tld と、個人 (ユーザー ID は nimrod) が所有する www.reckless.tld という、2 つのドメインを持つことになります。管理者は課題を解決するために、mod_proxy ソリューションを使うことを決めます。管理者は各ユーザーに対して、(プライベート IP アドレスとポートの組み合わせによる) そのユーザー固有の ID で実行する独自の Apache インスタンスを与えます。そして mod_proxy ソリューションを使って、またパブリック IP アドレスとポートの組み合わせで www-data として実行するファサード・サーバーを使うことで、どちらのユーザーのドメインにもアクセスできるようにします。この完全なシナリオを 図1 に示します。

図 1. サンプル・シナリオ
Example scenario

推奨の Apache バージョン

Apache 管理者は、このサンプル・アプリケーションの構成要素それぞれに対して、表 1 に示すバージョンの Apache を使う必要があります。

表 1. サンプル・アプリケーションで使われる Apache のバージョン
要素Apache のバージョン理由
ファサード・サーバーワーカーまたはイベント MPM を実行する Apache 2Apache 2 は、mod_proxy モジュールに対して重要な機能強化を行っています。ワーカー MPM とイベント MPM はスレッド化されているため、ファサード・サーバーのメモリー・オーバーヘッドを減らすことができます。
バックエンド・サーバーApache 1.3、または prefork MPM を実行する Apache 2Apache 管理者は、PHP モジュールがスレッド環境で実行されないように注意する必要があります。これら 2 つのソリューションは、PHP モジュールにプロセス・ベースの環境を提供します。

バックエンド Apache インスタンスの構成

リスト 23 のスニペットは、標準の Apache 構成とは異なる最も重要な構成上のポイントを説明しています。これらの内容は、必要に応じて追加する必要があります。例えばサンプルの構成では、PHP 機能を省略しています。

リスト 2. 起業したばかりのオンライン・ビジネスに対する Apache の構成
# Stuff every Apache configuration needs
ServerType standalone
LockFile /var/lock/apache/accept.startup.lock
PidFile /var/run/apache.startup.pid

ServerName necessaryevil.startup.tld
DocumentRoot "/home/startup/web"

# Essential modules
LoadModule access_module /usr/lib/apache/1.3/mod_access.so

# Which user to run this Apache configuration as
User startup
Group startup

# This must be off else the host isn't passed correctly
UseCanonicalName Off

# The IP/port combination to listen on
Listen 127.0.0.2:10000

# Using name-based virtual hosting allows you to host multiple sites per IP/port combo
NameVirtualHost 127.0.0.2:10000

<VirtualHost 127.0.0.2:10000>
ServerName www.startup.tld

# You can add aliases so long as the facade server is aware of them!
ServerAlias startup.tld

DocumentRoot "/home/startup/web/www.startup.tld"

<Directory /home/startup/web/www.startup.tld/>
Options Indexes FollowSymLinks MultiViews ExecCGI Includes
AllowOverride All
Order allow,deny
Allow from all
</Directory>

</VirtualHost>
リスト 3. 個人顧客に対する Apache の構成
# Stuff every Apache configuration needs
ServerType standalone
LockFile /var/lock/apache/accept.nimrod.lock
PidFile /var/run/apache.nimrod.pid

ServerName necessaryevil.nimrod.tld
DocumentRoot "/home/nimrod/web"

# Essential modules
LoadModule access_module /usr/lib/apache/1.3/mod_access.so

# Which user to run this Apache configuration as
User nimrod
Group nimrod

# This must be off else the host isn't passed correctly
UseCanonicalName Off

# The IP/port combination to listen on
Listen 127.0.0.2:10001

# Using name-based virtual hosting allows you to host multiple sites per IP/port combo
NameVirtualHost 127.0.0.2:10001

<VirtualHost 127.0.0.2:10001>
ServerName www.reckless.tld

# You can add aliases so long as the facade server is aware of them!
ServerAlias reckless.tld

DocumentRoot "/home/nimrod/web/www.reckless.tld"

<Directory /home/nimrod/web/www.reckless.tld/>
Options Indexes FollowSymLinks MultiViews ExecCGI Includes
AllowOverride All
Order allow,deny
Allow from all
</Directory>

</VirtualHost>

リスト 4 は、ファサード Apache インスタンスに対する構成を示しています。

リスト 4. ファサード Apache インスタンスに対する Apache の構成
# Stuff every Apache configuration needs
LockFile /var/lock/apache/accept.www-data.lock
PidFile /var/run/apache.www-data.pid

ServerName necessaryevil.facade.server
DocumentRoot "/home/www-data"

# Essential modules
LoadModule proxy_module /usr/lib/apache2/modules/mod_proxy.so
LoadModule proxy_http_module /usr/lib/apache2/modules/mod_proxy_http.so

# Which user to run this Apache configuration as
User www-data
Group www-data

# These must be set else the host isn't passed correctly
UseCanonicalName Off
ProxyVia On
ProxyRequests Off
# This must also be set, though it's only an option in Apache2
ProxyPreserveHost On    

# The IP/port combination to listen on
Listen 9.20.1.1:80

# Using name-based virtual hosting allows you to host multiple sites per IP/port combo
NameVirtualHost 9.20.1.1:80

# Configuration to forward requests for startup.tld
<VirtualHost 9.20.1.1:80>
ServerName www.startup.tld
ServerAlias startup.tld

ProxyPass / http://127.0.0.2:10000/
ProxyPassReverse / http://127.0.0.2:10000/
ProxyPassReverse / http://www.startup.tld:10000/
ProxyPassReverse / http://startup.tld:10000/
</VirtualHost>

# Configuration to forward requests for reckless.tld
<VirtualHost 9.20.1.1:80>
ServerName www.reckless.tld
ServerAlias reckless.tld

ProxyPass / http://127.0.0.2:10001/
ProxyPassReverse / http://127.0.0.2:10001/
ProxyPassReverse / http://www.reckless.tld:10001/
ProxyPassReverse / http://reckless.tld:10001/
</VirtualHost>

ここに示した ProxyPreserveHost ディレクティブは重要ですので注意してください。このディレクティブは Apache 2 に付属しており、バック・エンド・サーバーに正しい HTTP ヘッダーを転送する上での問題の一部が解決されています。ファサード・サーバーには Apache 2 インスタンスを使うように、強くお勧めします。

サンプル構成を実行する

ルート・ユーザーが、それぞれの構成を実行する必要があります。Apache は、ホスティング関連の全プロセスに対する構成ファイルに示されている特権を持ちます。リスト 5 は、起動の方法を示したものです。

リスト 5. サンプル・サーバーを起動する
/usr/sbin/apache -f /etc/apache/startup.tld.conf
/usr/sbin/apache -f /etc/apache/nimrod.tld.conf
/usr/sbin/apache2 -f /etc/apache2/facade.tld.conf

mod_proxy による方法の制限

重要な注意点として、この記事で概説した方法は、SSL 接続が必要なドメインには使えません。これは、SLL プロトコルがドメインの仮想ホスティングを許さないためです。この制限のため、SSL のホスティングは、各 SSL ドメインが固有の IP とポートの組み合わせでホストされる形で行われる必要があります。これはすべての Apache 構成に共通する制限であり、mod_proxy によるソリューション特有の制限ではありません。そのドメイン所有者のユーザー ID を使えば、SSL が必要なドメインでも実行することができます。


まとめ

この記事では、Apache の mod_proxy モジュールの機能を使って、2 台のバックエンド・サーバーにリクエストを転送するファサード・サーバーで構成される環境を構築しました。この記事で説明した同じ原理を、何台ものバックエンド・サーバーを使用する場合にも適用することができます。システム管理者は、この手法を使うことで潜在的なセキュリティー・リスクを分離できる一方、PHP のようなツールの柔軟性を活用することができます。

参考文献

学ぶために

  • Apache から、suEXEC サポートに関するドキュメンテーションを入手してください。そして、皆さんのユーザーがプライベートな CGI プログラムや SSI プログラムを開発し、実行する際のセキュリティー・リスクを減らすための方法を学んでください。
  • MetuxMPM Wiki からこのモジュールに関して学び、そして Apache Web サーバー (そして Perchild MPM への後継) に対する MPM (Multi Platform Module)に貢献してください。
  • 一般的なビジネス問題を解決する上での LAMP、つまり Linux-Apache-MySQL-PHP による Web 開発フレームワークへの入門を紹介したチュートリアル、「Introduction to LAMP technology」 (Jono Bacon 著、developerWorks、2005年5月) を活用してください。
  • developerWorks Web development ゾーンには、LAMP を含めたさまざまな Web 開発技術に関する記事が豊富に用意されています。
  • developerWorks の Linux ゾーンに用意された、最新の Linux 技術に関する豊富な資料を活用してください。
  • Technology bookstore には、この記事に関連した本の他、さまざまな話題に関する技術書が豊富に用意されています。
  • developerWorks technical events and webcasts は充実した内容の技術セッションです。皆さんの学習期間を短縮し、また困難なソフトウェア・プロジェクトの品質や結果を改善する上で役立つはずです。

製品や技術を入手するために

  • peruser MPM の実動実装である metuxmpm に基づく Apache 2 モジュール、peruser MPM について調べてください。
  • IBM trial software を利用して皆さんの次期開発プロジェクトを構築してください。developerWorks から直接ダウンロードすることができます。
  • developerWorks Web Development Downloads and products area には、無料のダウンロードが豊富に用意されています。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。プロフィールで選択した情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Web development, Linux, Open source
ArticleID=237585
ArticleTitle=Apache Proxy のディレクティブ (mod_proxy) を使って LAMP セキュリティーを改善する
publish-date=11292006