読者です 読者をやめる 読者になる 読者になる

人間とウェブの未来

「ウェブの歴史は人類の歴史の繰り返し」という観点から色々勉強しています。

VirtualHostを用いた共有レンタルサーバは静的コンテンツも権限分離しなければならない

共有レンタルサーバのWeb機能提供において、単一のApache httpdでVirtualHost機能により複数のホストを仮想的に処理する場合が多く、その際に重要になってくるのがCGI等の動的コンテンツを適切に権限分離しセキュリティを担保する事です。

静的コンテンツの権限分離の必要性

しかし最近では、動的コンテンツだけでなく静的コンテンツも権限分離をしないと、共有レンサバのように各ホストが自由にファイルを操作できる状況では、セキュリティ上の問題があるという話が出てきました。

具体的には、シンボリックリンクをApacheで無視する設定にしていたとしても、各ホストの管理者(共有レンサバのユーザ)がシンボリックリンクをファイルシステム上に作成できてしまう時点で、悪意のあるユーザがApacheの仕様に伴うシンボリックリンク検査のレースコンディション問題を利用してシンボリックリンクを自由に設置し、他のホスト領域のファイルを閲覧できる可能性がある、という問題です。

このようなセキュリティ上の問題がある以上、共有レンサバ提供側は適切に静的コンテンツの権限分離も行い、きちんとこの問題を解決していかなければなりません。しかし、静的コンテンツの権限分離のためにサーバプロセスをfork()してsetuid()で権限分離や、あるいは、僕が以前に開発したmod_process_securityのようにthreadを生成して権限分離するには、リクエスト単位でプロセスやスレッドの生成・破棄が必要で、性能面でコストが高くなるという課題がありました。

また、特定のMPM、例えばpreforkモデルを要求する、あるいは、FastCGIのようなモデルでの権限分離では大規模VirtualHost環境において各ホストのownerにあらかじめsetuid()した専用のプロセスを起動させておく必要がありプロセス数が膨大になりメモリ量が増加する、等の問題がありました。

静的コンテンツの権限分離可能なApacheモジュール

そこで、静的コンテンツでも性能面で低コストに各ホスト毎に権限分離を行えるApacheモジュールmod_fileownercheckを先日作りました。このモジュールでやっている事を以下に簡単にまとめます。

処理1

  • Apacheがファイルをopen()した段階で、そのファイルがシンボリックリンクだった場合、シンボリックリンク自体のownerと、シンボリックリンクが指し示すopen()されたファイルのownerをfdから取得して比較し、同一であれば許可
    • これはopen()する前段で、リクエストのあったファイルがシンボリックリンクであるかをApacheがチェックするのですが、そのチェックのタイミングでシンボリックリンクでなかったとしても、その後のopen()が行われるタイミングのわずかの間でファイルを他の領域のファイルを指し示すようなシンボリックリンクにすり替えられ場合、他の領域のファイルを閲覧できる問題があるため、このチェックが必要になります。

処理2

  • Apacheがファイルをopen()した段階で、fdからownerを取得し、そのownerとSuexecUserGroupで設定しているownerを比較して同一であれば処理を続行
    • これはopen()する前段で、リクエストのあったファイルパスの途中にシンボリックリンクがあるかをApacheがチェックする場合に、そのチェックに問題がなくとも、その後のopen()するまでのわずかの間に途中のディレクトリ等をシンボリックリンクに置き換えられた場合、他の領域のファイルを閲覧できる問題があるため、このチェックが必要になります。
    • この場合は処理1のようにリクエストファイルのownerチェックを行うだけでは十分ではない(リクエストファイルパスの途中にシンボリックリンクを置かれていた場合、open()したファイルのownerと現在のファイルのownerが他のユーザのowner同士で一致してしまう)ので、open()したファイルがそのホストのownerのファイルであるかを静的に解析する必要があり、SuexecUserGroupからそのホストのownerであることをチェックするようにしています。
    • このような環境では動的コンテンツも通常、SuexeUserGroupで権限分離しているだろうという想定の元です。

このように、静的ファイルであってもシンボリックリンクをファイルシステムに作成できてしまう以上、こういった権限分離処理が必要になります。

特に、処理2のリクエストファイルパスの途中のディレクトリがシンボリックリングの場合の対処は見逃されがちなので今一度確認してみた方が良いと思います。

mod_fileownercheckの使い方

そこで、静的コンテンツの権限分離を行ってくれるmod_fileownercheckでは以下のようにApacheモジュールを読み込むだけで、上記のような静的ファイルの検査を行ってくれます。

LoadModule fileownercheck_module modules/mod_fileownercheck.so

また、リクエストファイルパスの途中にシンボリックリンクが含まれている状況を対処するためのSuexecUserGroupの設定値から静的にownerを検査する処理は、必要としない状況や検査をあえてしたくない領域(ユーザに提供していない管理領域など)もあると思うので、デフォルトはOFFにしておき、新規でディレクティブを実装して以下のように特定の領域のみに設定できるようにしました。

<Directory /var/www/html/vhost/*/htdocs>
  FOCSuexecEnable On
</Directory>

上記の設定では、ユーザに提供するVirtualHost領域、つまり、SuexecUserGroupで動的コンテンツの権限分離を行っている領域において、同様にSuexecUserGroupのowner値を利用した静的コンテンツの権限分離を行うようにしています。

まとめ

ということで、VirtualHostを使った共有レンサバでは、セキュリティを担保するために動的コンテンツだけでなく静的コンテンツを権限分離しなければならない状況になっています。

そのために、まずはレンサバの管理者が使いやすい、あるいは、現行のシステムに導入しやすいように上記のような仕様の静的コンテンツの権限分離モジュールmod_fileownercheckを作りました。

ApacheのVirtualHostを用いた共有レンサバでまだ静的コンテンツの権限分離をおこなっていない方は是非ともmod_fileownercheckを導入することをおすすめします。

また、新たな問題が起きた場合は、mod_fileownercheckにpull-reqeustやissueをあげていてだければ対応しますので、この辺りのレンサバに絡んだセキュリティ情報はやっぱり業界全体で共有していきたいですね。