Home

人間とウェブの未来

共有WebホスティングでVitrualHost設定に手を入れずにシンボリックリンクのTOCTOU問題を解決するApacheモジュールを作った


共有Webホスティングを提供している業者の皆様は、シンボリックリンクのTOCTOU問題というかなりクリティカルで必ず対応すべき問題をおそらく様々な方法によって解決されていると思います。

しかし一方で、TOCTOU問題をなんとなく放置されている、あるいは、誤解されている場合もあるかもしれません。この問題は、Apacheでシンボリックリンクを使えない(シンボリックリンクにアクセスがあったら4系エラーを返す)設定にしていたとしても、シンボリックリンクファイルを作る事さえできれば、攻撃プログラムを使う事により、apache権限でアクセス可能なファイルにシンボリックリンク経由でアクセスすることが可能となります。また、Apache本体のコアに直接パッチを当てて対応されている方も多いでしょう。

その場合、

  • コアのパッチは今後Apacheのバージョンアップに伴いメンテが面倒になる
  • 幾つか公開されているモジュールは設定の変更箇所が多いので困っている
  • TOCTOU問題をあまりよくわかってない

という状況があると思います。

そこで、あまり既存の共有ホスト、例えばVirtualHostの設定等を変える事なく簡単な設定を追記するのみで共有WebホスティングのTOCTOU問題を解決するApacheモジュールmod_fileownercheckを作りました。

追記1:SetOutputFilterの設定をしなくて良いようにした

インストールは簡単で、apxsでビルドした後いつも通りモジュールをLoadModuleするだけで良いです。

モジュールをロードするだけで、シンボリックリンクのTOCTOU問題を解決できます。ホスティング業者によっては、共有ホスティングの構成が様々でこのモジュールだけでは対応出来ない場合もあると思います。ですので、一度攻撃プログラムを用いて試した上で利用するのが良いと思います。VirtualHost + suEXEC + Directoryのパーミッションのような定番の共有ホスティングの場合は、大抵このモジュールだけで解決できると思います。

仕組み的には単純で、リクエストのあったファイルがApacheによってopenされた時点で、そのopenされたファイルのownerとリクエストのあったファイルパスのownerが一致するかをチェックするものです。

追記2:.htaccessでの上書き防止処理やリクエストパスの途中にシンボリックリンクを含んでいる場合の対処を追加

さらに、.htaccessで上書きできないようモジュールで強制的にoutput filterに追加するようにしました。また、リクエストパスの途中に他のユーザのディレクトリを指すシンボリックリンクが含まれている場合も対応するために、suEXECで設定しているownerとopenしているファイルのownerチェックも行うようにしました。

もしまだApacheのバーチャルホスト等で構築した共有Webホスティングを提供しながら、このTOCTOU問題の対応をされていなかったり、コアに手を入れていたりする場合は是非このmod_fileownercheckをご活用下さい。また、問題がありそうでしたらレポジトリにissueやpull-requestをして頂けると幸いです。

apache bench(ab)コマンドをRubyで拡張できるab-mrubyのDockerイメージを公開


ab-mrubyとはapache bench(abコマンド)のパラメータ設定や、ベンチマーク結果のテストをRubyで書けるベンチマークツールです。今回はそのab-mrubyコマンドのDockerイメージを作りました。

僕みたいにabコマンドを毎日のように使うエンジニアにとっては、ab-mrubyはそれなりに有用だと思っていたのですが、mrubyをビルドしたりaprを使ってabをビルドしたりいまいち使いにくいなぁと思っていました。しかしそれがDockerの登場によって面倒な所はほとんどラッパーできるようになり、ab-mrubyのDockerイメージを作る事によって必要な部分だけを弄ってすぐにab-mrubyを使えるようにしました。

自身のクライアントPCにDockerを入れるのは気軽にできると思うので是非一度遊んでみてください。

ab-mrubyについてご存じない方は以下のエントリを御覧ください。

最新のab-mrubyはGitHubにて公開しています。

簡単な使い方

ab-mrubyに関しては、上記のエントリに書いているので、今回は簡単な使い方の説明のみにします。

まずはab-mrubyのDockerイメージをDocker Hubからpullして下さい。

sudo docker pull matsumotory/ab-mruby

そして、実際に実行してみましょう。docker runコマンドに加えて最後の引数にURLを指定してやるだけでab-mrubyを試すことができます。

$ sudo docker run matsumotory/ab-mruby http://blog.matsumoto-r.jp/
======================================================================
This is ab-mruby using ApacheBench Version 2.3 <$Revision: 1430300 $>
Licensed to MATSUMOTO Ryosuke, https://github.com/matsumoto-r/ab-mruby

                          CONFIG PHASE

======================================================================
  Target Information  URL: http://blog.matsumoto-r.jp/
  Target Information HOST: blog.matsumoto-r.jp
  Target Information PORT: 80
  Target Information PATH: /
  Target Information  SSL: false
======================================================================
This is ab-mruby using ApacheBench Version 2.3 <$Revision: 1430300 $>
Licensed to MATSUMOTO Ryosuke, https://github.com/matsumoto-r/ab-mruby

                            TEST PHASE

======================================================================
[TEST CASE] [true] FailedRequests (0) should be 0
[TEST CASE] [true] WriteErrors (0) should be 0
[TEST CASE] [true] CompleteRequests (100) should be 100
[TEST CASE] [true] TransferRate (1179.60901260841) should be over 500
[TEST CASE] [false] RequestPerSecond (18.4716961893629) should be over 1000
[TEST CASE] [true] TimePerRequest (54.1368799999999) should be under 100
[TEST CASE] [true] TimePerConcurrentRequest (541.368799999999) should be under 3000
[TEST CASE] [true] ConnetcErrors (0) should be 0
[TEST CASE] [true] ReceiveErrors (0) should be 0
[TEST CASE] [true] LengthErrors (0) should be 0
[TEST CASE] [true] ExceptionsErrors (0) should be 0
[TEST CASE] [true] Non2xxResponses (0) should be 0

test suites: [false]

すると、予めRubyで記述したベンチマークパラメータとテストケースによって実行されたベンチマークとテストの結果が得られます。おおおお、RequestPerSecondがテストケースの値より低く出ているのでテストが失敗していますねー、とかがわかります。

Rubyでベンチマークパラメータやテストを書いて自分専用のDockerイメージを作る

ab-mrubyのDockerイメージはab-mruby/docker/ディレクトリ以下のRubyで書かれたベンチマークパラメータとテストケースのサンプルを元に実行されています。それらを自分なりに変更したい場合は、

git clone https://github.com/matsumoto-r/ab-mruby.git
cd ab-mruby
vi docker/ab-mruby.conf.rb
vi docker/ab-mruby.test.rb
sudo docker build -t local/ab-mruby .
sudo docker run local/ab-mruby http://blog.matsumoto-r.jp/

ab-mruby.conf.rbにベンチマークパラメータを、ab-mruby.test.rbにテストケースを書くと、自分なりのベンチマークパラメータやテストケースを反映した自分専用のDockerイメージを作成する事ができます。自由にGitHubからforkして頂き、そこからDocker Hubと連携してベンチマークイメージを作るのも良いと思います。

書き方は、

上記に上げたab-mrubyに関するエントリやab-mrubyのGitHubレポジトリを参考にして下さい。

ab-mrubyのDockerイメージを使って有意義なベンチマークライフを過ごしてみてはいかがでしょうか!

Apacheのシンボリックリンク検査に関するTOCTOU問題をmod_mrubyで解決してみた


共有ホスティングにおいて、各利用ユーザに対してシンボリックリンクの使用を許可していた場合に、他のユーザ領域のコンテンツを閲覧できたりする問題があるため、SymLinksIfOnwerMatchの設定によりリンクのownerとリンク先のファイルのownerが一致していない限りはリンクを辿らないようにする対処がされてきましたが、そもそもリンクの検査とファイル作成のタイミングによっては、検査をすり抜け、閲覧を可能にするTOCTOU問題がありました。

この件に関しては、「Apache HTTPD: `Options -FollowSymLinks` は不完全」に詳しく解説されているのでそちらを見て頂くとして、リンク使用は許可しつつもそのTOCTOU問題を解決するための一つの方法として、open()したコンテンツファイルのfdから情報を検査してownerに不一致があった場合はレスポンスを返さないようにする、というアプローチがあります。

実装として、Apache本体に手を入れたり、Apacheモジュールで対応したり、といくつか方法がありますが、今日はWebホスティングのセキュリテイとmod_mrubyの実装の復習がてら、単純な静的コンテンツへのリクエストにおけるこの問題をmod_mrubyで楽に解決できるようにしてみました。

具体的には、コンテンツがopen()されているアウトプットフィルターフェイズにおいてmod_mrubyで介入し、任意のuidと、open()されているコンテンツのuidが異なっていたらエラーを返す、という処理を書きました。

まずは、Apacheの設定を以下のようにして、

SetOutputFilter mruby
mrubyOutputFilter /path/to/solved_link_toctou.rb

/path/to/solved_link_toctou.rbを以下のようにします。

uid = 1000

f = Apache::Filter.new

if f.uid != uid
  f.error_create Apache::HTTP_SERVICE_UNAVAILABLE
end

このように実装することで、f.uidメソッドから既にopen()されたファイルのuid情報を取得できるので、TOCTOU問題を気にすることなくownerのチェックを行えます。上記の例の場合では、openしたコンテンツのuidが1000じゃなければ503エラーを返し、一致すれば何もせずにリクエストのあったコンテンツの内容をそのまま返します。後は幾つか細かい点があるのですが、それを書くと内容が広がりすぎるので一旦はこの程度の検査に留めておきます。

というわけで、mod_mrubyのリハビリがてら、SymLinksIfOnwerMatchTOCTOU問題をmod_mrubyで解決してみました。mod_mrubyだと非常に簡単に書けるので楽でした。

chmodやchownのreferenceオプションを知った時は目から鱗だった話


元々ホスティング会社で働いていたので、その特性上ownerやpermissionを色々と弄る事が多く、数年前の社会人時代にchmodやchownをもっと楽に使えないかなぁと調べた時に目から鱗だったのがchmodやchownのreferenceオプションでした。

今回は単にreferenceオプション楽ですよね、という記事なのでご存知の方は退屈な記事だと思いますが、まわりに聞いてみた所意外と知られていなかったりしたので、ブログエントリにしておこうと思います。

referenceオプションを使うと、任意のファイルを指定することで、変更対象のownerやpermissionを指定したファイルと同じ設定にすることができます。

例えば、/bin/pingみたいなpermissionって僕は覚えられなくて通常の実行方法ではわりと面倒だと思うのですが、それと同じowner、permissionにしたい場合は、

$ ls -l /bin/ping
-rwsr-xr-x 1 root root 44168 May  7 14:51 /bin/ping
$ touch myprogram
$ ls -l myprogram
-rw-rw-r--  1 matsumotory matsumotory         0 Jun 22 21:10 myprogram
$ sudo chown --reference=/bin/ping myprogram
$ sudo chmod --reference=/bin/ping myprogram
$ ls -l myprogram
-rwsr-xr-x 1 root root 0 Jun 22 21:05 myprogram

みたいな事ができるので、大変楽になります。本来は、chmodとchownを使いまわす際に755とかmatsumotry.matsumotryとか引数を書きなおして実行する必要があったのに対し、referenceオプションを使うとchownとchmodのown文字列とmod文字列を3文字変更するだけで達成したい変更処理が実現できるのも、キーボード的にも省エネで気に入っています。

というわけで、単なるネタ記事になってしまいましたが、どうぞreferenceオプションをよろしくお願いします。

Dockerとmrubyで迅速かつ容易にnginxとapacheの柔軟なリバースプロキシ構成を構築する


Docker Hubがアナウンスされて以来、焦ってDockerを触っている@matsumotoryです。

今日は早速mod_mrubyngx_mrubyをdocker buildに対応させました。これによって、Docker環境においてmod_mrubyを組み込んだApache httpdやngx_mrubyを組み込んだnginxを迅速かつ容易に連携させる事ができるようになります。

今日はその一例を紹介したいと思います。

全文を読む

Home

検索
フィード
メタ情報

Return to page top