2015年4月30日木曜日

Apacheの多重拡張子にご用心

先日の日記『「10日でおぼえるPHP入門教室 第4版」はセキュリティ面で高評価』では、同書のアップロード機能のセキュリティ面を評価しつつ、「もうひと踏ん張り確認して欲しい内容がある」として、画像XSSの可能性について指摘しました。では、これを直せば完璧かというと、実はそうとも言えないという微妙な問題があります。それは、アップロード先の場所とファイル名の問題です。
ファイルをアップロードするディレクトリ: ドキュメントルート下の /php10/doc/
ファイル名: ブラウザから送信されたファイル名そのまま
これらのうちファイル名の拡張子については、gif/jpg/jpeg/pngのみを許すという、いわゆるホワイトリスト検査がされていて、またgetimagesize()関数により、画像ファイルであることの簡易的なチェックをしています。しかし、この状態では、環境によってはアップロードしたファイルをPHPスクリプトとして実行される危険性があります。

同書は、その種の危険性を考慮して、以下の様な注意書きを書いています(同書P214)。
COLUMN: ファイル名の保存先には要注意

同書では、サンプル実行の簡単さを優先して、ドキュメントルートの配下にアップロードファイルを保存しています。しかし、これは不正なファイルをアップロードされたときに、そのまま実行されてしまう危険もはらんでいます。
一般的には、アップロードファイルは、ユーザーが直接アクセス出来ない--ドキュメントルートの外に保存するようにしてください。
これは実に正しい指摘ですが、それでは拡張子のホワイトリストチェックをしても、どうしてスクリプト実行されるかという疑問が生じます。その方法の一つが、Apacheの多重拡張子を悪用するという方法です。

多重拡張子

Apacheは元々の仕様として多重拡張子を扱えるようになっていて、その代表例はApache自身のマニュアルファイルに見ることができます。Apacheのマニュアルファイルには、以下のように各言語用のコンテンツが並んでいます。
index.html.en
index.html.fr
index.html.ja.utf8
最後の例だと、htmlに加えて、ja(言語=日本語)とutf8(文字エンコーディング=UTF-8)という具合に三種類の拡張子がついています。
これは、Apacheのディレクティブの中に拡張子によって挙動を変えるものが複数存在するためにおこる問題です。

ファイル名の途中にあるphp拡張子でスクリプトが起動する場合

このため、設定にもよりますが、phpinfo.php.png等ファイル名の末尾以外でも.php.が含まれていると、ApacheがこのファイルをPHPスクリプトとして判断してスクリプトを起動してしまう場合があります。具体的には、AddHandlerにより以下のようにPHPスクリプトを設定している場合が該当します。
AddHandler php5-script .php
そのような環境がどれくらいあるかは分かりませんが、メジャーなところではRHEL/CentOSが該当するので、影響は広範囲に渡りそうです。

「10日でおぼえるPHP入門教室 第4版」の環境は該当しない

それでは、「10日でおぼえるPHP入門教室 第4版」の環境(XAMPP)はどうかというと、PHPのApache設定は下記の通りで、この場合は上記の問題に該当しません。
#
# PHP-Module setup
#
LoadFile "C:/xampp/php/php5ts.dll"
LoadModule php5_module "C:/xampp/php/php5apache2_4.dll"

<FilesMatch "\.php$">
  SetHandler application/x-httpd-php
</FilesMatch>
従って、「書籍に書いてある通りに動かす分には脆弱性ではない」ということになります。冒頭で「微妙な問題」と書いた理由はこれです。

同書のスクリプトをCentOS上で動かすとスクリプト実行の脆弱性が発現する

しかし、同書でPHPを勉強した読者が、レンタルサーバー等を借りて自作のスクリプトを動かすと、脆弱性が悪用される危険性が生じます。
検証に必要な画像ファイルの作り方は、以前のエントリと同様で、JavaScriptの代わりにPHPスクリプトを書くだけです。そのようにして作成したファイルをアップロードしてブラウザからアクセスした様子を示します。実験にはCentOS6を用いました。


対策

対策には複数の種類があります。いずれか一つで対策になりますが、適宜複数を組み合わせることで安全性が高まります。推奨は (3)と(4)の組み合わせです。

(1)Apache側の設定を変える
XAMPPで用いている方法でPHPスクリプトを動かすようにする方法です。この場合は、ファイル名末尾が .php の場合のみPHPスクリプトとして動作するので、アプリケーション側の拡張子チェックをすり抜けることはありません。

(2)ファイルのアップロードディレクトリでPHPが動かないようにする
アップロードファイルがドキュメントルート配下に置かれる場合、該当のディレクトリでPHPが動かないようにする方法があります。httpd.confや.htaccessにて以下の設定を指定します。
RemoveHandler .php
この方法を推奨するというわけではありませんが、既存のアプリケーションで緊急対処が必要な場合には役立つでしょう。設定後、無害な test.php.png などのスクリプトでPHPとして動かないことを検査することと、検査後はそのファイルを必ず削除することを忘れないで下さい。また、php以外の拡張子を環境に応じて設定して下さい。

(3)アップロードファイルをドキュメントルート配下に置かない
この方法を強く推奨します。同書注意書きにもあるとおりですし、拙著『体系的に学ぶ 安全なWebアプリケーションの作り方 』でもこの方法を推奨しています。

(4)ファイル名を付け替える
そもそもブラウザから送信されたファイル名をそのまま使ってファイルを保存するという仕様はよくありません。ファイル名の衝突がありえるからです。ファイル名は他と衝突しないユニークなものを採番してつけるようにしましょう。これも拙著で推奨している方法です。これは、セキュリティ要件以前のアプリケーション要件として必要ですね。

まとめ

Apacheの多重拡張子の危険性と対策について説明しました。Apacheの多重拡張子は脆弱性ではなく仕様ですので、できればアプリケーション側で対処した方がよいと私は考えます。対策として説明した(3)と(4)は、Apache以外の環境でも安全性に寄与するため、強く推奨する方法です。
ファイルのアップロードはPHPから簡単にできてしまうので、PHP入門書でもしばしば取り上げられていますが、セキュリティの面からは危険な実装になっている場合が多いです。インターネットに公開するためには、セキュリティを強化する必要があります。
入門書だからそれでも仕方ないではないかという意見もあるでしょうが、私はそうは思いません。多くの読者は、それが危険な方法と知らないままに、その方法でインターネット上のサイトを作り続けるでしょう。最初から安全な方法を紹介するか、ファイルアップロード機能の紹介を諦めるか、どちらかです。つまり、ファイルのアップロードは、実は簡単ではないととらえるべきだと思います。

参考



【HASHコンサルティング広告】
この記事はHASHコンサルティング勤務中に書かれた。
HASHコンサルティング株式会社は、本物のセキュリティエンジニアを募集しています。
興味のある方は、twitterfacebookのメッセージ、あるいは問い合わせページからお問い合わせください。


0 件のコメント:

コメントを投稿

フォロワー