Webサーバを構築する上で、複数のユーザーでサーバを共有する場合、Apacheの仮想ホスト方式(VirtualHost)を使う場合が多いと思う。この方式の利点としては、単一のサーバプロセスのみを動作させておけば良く、リソース効率が良いからだ。
個別のユーザーごとにサーバプロセスを立ち上げたり、chrootで区別したり、仮想マシンやコンテナ等で区別する手法があるが、Webサーバを共有したい目的においては、非常にオーバースペックな共有の仕方と言える。そのため、仮想ホスト方式を使う場合が多いのだが、ここでよくよく注意しなければならないことがある。
それは、セキュリティである。
仮想ホスト方式は単一のサーバプロセスで複数のユーザーを処理するため、サーバプロセスの権限で各ユーザー領域のファイルやディレクトリを処理できるようにパーミッション設定をしておかなければならない。その際に、例えば、あるユーザーがCGIのプログラム内部で以下のような外部コマンドを実行した場合、問題が起きる。
cat /var/hosts/fuga2.com/htdocs/index.php
このコマンドによって、別のユーザーのデータベースパスワードが書かれているようなスクリプトから、容易にパスワードが奪取できてしまう。例えば、以下のようなディレクトリ構成とパーミッション設定だったとしよう。
この場合、index.cgiをApacheの権限であるuid500,gid101で実行する。/var/hosts/fuga2.com/ディレクトリはgid101からの読み取り権限がある。さらに、ディレクトリ配下のホスト領域内部のファイル群はApache権限でアクセスできるように全ユーザーに読み取り権限がある。そのため、 index.cgi内でシェル等の外部コマンドを実行することで他ホストfuga2.comのindex.cgiのソースコードを閲覧しデータベースパスワード等を入手できる。
また、Web API等によってプログラムを設置していた場合も、バグによって関係のないファイル等を操作してしまう恐れや、脆弱性を突かれた場合、Webサーバ上で管理している全てのファイルが危険な状態となり、被害が大きくなる。そこで、CGI実行方式に利用できるアクセス制御モジュールであるsuEXEC 機能を用いると、上記のようなリスクを低減できる。以下にsuEXECの利用例を示す。
上記は、その上の図と同様のパーミッション設定をしている。しかし、suEXECを採用すると、クライアントからCGIにアクセスがあった場合、ApacheによってCGIの実行処理をsuEXECに依頼する。suEXECはindex.cgiを実行する際に、index.cgiの権限であるuid501,gid102をサーバ設定から取得する。そして、プロセスの権限を変更するシステムコール(以降setuid,setgidとする)を実行して、プロセスの権限を変更し、CGIを実行する。そのため、uid501・gid102の権限では、 /var/hosts/fuga2.com/配下での読み取り権限であるuid502、gid101がない。
このように権限変更を行うことで、他ホスト領域へのアクセスやhoge1.com経由でfuga2.comのindex.cgiの閲覧を防止できる。また、Web APIのプログラム群も用途別に適切に権限を分けておく事で、Apache権限に統一して権限許可をする必要が無く、権限で区別されたプログラム群の範囲内で処理を行うことができる。脆弱性を突かれたプログラム経由の被害も、同一の権限内に収めることができる。
さらっと書いたこのディレクトリとパーミッションの設定は、個人的に知る限りもっとも安全で使い勝手の良い設定だと思っている。Webサーバの仮想ホスティングにおけるパーミッション設定の答えではないだろうか。
しかし、世の中には、以下のようにユーザーに割り当てられる仮想ホスト単位でuidとgidを個別に統一し、ドキュメントルートのパーミッションを701等にしている場合が多い。
このパーミッション設定はサンプルとして非常に良く見かける。suEXECを行えば、一見他の仮想ホスト領域にアクセスできないように見えるが、実は全くダメダメなパーミッション設定なのである。パーミッション701の1は、ファイルのuid、gidとは違うそれ以外のユーザーからアクセス可能で、サーバプロセスがリクエストを受けた際に内部でそのファイルに対するパスを解析し、そのファイルに実際にアクセスをするために必要なパーミッションである。つまり、パスが分かっていればこのドキュメントルートのパーミッション設定では任意のファイルにアクセス可能だということことになる。
さらに、ホスティングのディレクトリ構成は同じような場合が多い上、OSSのCMSはファイルやディレクトリ構成が公開されている。そのため、自分の環境やURLと照らし合わせて簡単に推測することができる。ドキュメントルートのパーミッションに701の1がある限り、他ユーザーはパスワードが書かれたPHPプログラムをシェルでcatし放題なのだ。かといって、ドキュメントルートは以下のそれぞれのファイルをMASKで700となるようにしていると、そもそもサーバプロセスからアクセスができない。これも、サーバプロセスがrootで起動していれば可能だが、それはもっと危険なセキュリティリスクをはらんでいるはずだ。そのため、仮想ホストでWebサーバを共有する場合は、uidとgidを適切に使ってパーミッション設定をする必要がある。
以上から、最初に説明したパーミッション設定が、suEXECを使う上では安全で、なおかつ仮想ホストのユーザー領域でユーザーがパーミッションを気にしなくて良い設定となっている。もし、自分の借りているサーバでパーミッション設定をチェックして、良くない設定になっていれば危険な状態だと認識しても良いかもしれない。さらに、そうだったとしても、他の顧客領域を覗き見するような真似は絶対にしてはいけない。
サーバ管理者は常にそういう輩を監視しているのだ。
「Webサーバの仮想ホスティングにおけるパーミッション設定の答え(Apacheの場合)」への2件のフィードバック
コメントは受け付けていません。