なぜPHPアプリにセキュリティホールが多いのか?

第22回文字エンコーディングとセキュリティ(4)

今回で文字エンコーディングとセキュリティをテーマとした解説は終了です。前回はSJIS文字エンコーディング特有の問題を解説しました。今回は文字エンコーディングとちょっと違ってはいても、文字エンコーディングに関連したセキュリティ上の問題を簡単に紹介します。

文字列の正規化を利用した攻撃

日本語の文字エンコーディングの場合、同じ文字でも違う文字コードが割り当てられています。最も分かりやすい例は半角カナと全角カナです。同じ文字であっても、違う文字コードが割り当てられています。人間が文章を読むには半角カナでも全角カナでも同じように読めますが、コンピュータはそうはいきません。

同じ意味の文字であれば統一した文字コードに置き換える操作を「文字列の正規化」と呼びます。文字列を正規化することにより、文字コードの違いを無視して、文字の意味で文字列を利用できるようになります。好ましいことですが、これが問題となる場合があります。

例えば、正規化を行うと⁠\⁠(半角バックスラッシュ)⁠\⁠(全角バックスラッシュ)が同じ⁠\⁠(半角バックスラッシュ)になったりします。現在のPHPでは文字列を自動的に正規化して処理するような機能が標準として用意されていません。私の知る限りでは、文字列の正規化を利用した攻撃が可能になったアプリケーションはまだありません。しかし、Java系やASP.NET系のアプリケーションでは、ディレクトリ遷移攻撃などが度々発見されました。

対策:

正規化やデコード等、すべての変換処理が終わってから、バリデーション処理する。

文字エンコーディングや文字列の正規化に限ったことではありませんが、デコードや正規化などの変換が必要なデータの場合、すべてのデコード、正規化などの変換処理が終わってからデータをバリデーションしなければなりません。

今回の記事では詳しく解説しませんが、不必要なエンコードとデコードは脆弱性の原因になります。デコード済みのデータを不必要に再デコードしたために脆弱性が発生した実例もいくつもあります。デコードを複数回行うと、デコードのたびにバリデーション処理が必要になりますが、バリデーションを行わないとそのために脆弱性が発生します。こう書くとデコードのたびにバリデーションをすればよい、思われるかも知れませんが、デコード処理は本来一回だけ実行されるべきです。

文字列の正規化は、本稿の範囲外です。詳しくは、Unicode関連の仕様を参考にしてください。

その他のエンコーディングを利用した攻撃

エンコーディングと名前が付くデータ形式すべてに、なんからの攻撃手法が潜んでいる、と考えたほうが安全です。Webアプリケーションでは、バイナリデータやバイナリに近いデータ(マルチバイト文字など)を取り扱う場合、ASCIIコードでデータが表現できるよう、URLエンコーディング(%00、%20など)を利用します。⁠"⁠(ダブルクオート)⁠/⁠(スラッシュ)やヌル文字などを、⁠%⁠を使ってエンコードします。

URLエンコーディングを利用して、通常のテキストには挿入されないヌル文字、改行文字などを挿入して攻撃されることがあります。最近のフレームワークや関数は、ヌル文字攻撃、改行文字の挿入によるヘッダ分割攻撃などが行えないようになっている場合が多いです。しかし、アプリケーション開発者も文字列中に不正な制御文字、特殊文字が含まれていないか、チェックをしなければなりません。文字のエンティティ化もよく知られた攻撃方法です。エンティティ化もエンコーディングを利用した攻撃の一種と考えてよいでしょう。

Data形式URIを利用した攻撃もエンコーディングを利用した攻撃と言えます。Data形式URIはバイナリデータをHTMLページに埋め込めるため便利な場合があります。Data形式URIはBASE64エンコードされたテキストデータです。JavaScriptが埋め込まれていても、テキストとしてチェックしているだけでは、攻撃を防げません。

Data形式URIを用いた攻撃のサンプル
<META HTTP-EQUIV="refresh" CONTENT="0;url=data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K">

出典:XSS Cheat Sheet

Data形式URIを利用したJavaScriptインジェクション等の手法は、よく知られた攻撃方法です。この種類の攻撃を防ぐには、ホワイトリスト方式で文字列をチェックし、Data形式URIを利用できないように制限します。

文字エンコーディングを利用した攻撃への対策のまとめ

文字エンコーディングが正しいかチェックするのは、アプリケーションプログラマの責任だと考えてください。フレームワークやライブラリ側、サーバ側だけでは対処しきれないからです。

もう一度、文字エンコーディング等を利用した攻撃を防ぐための対策を記載します。

文字エンコーディング取り扱いの原則

文字エンコーディングは厳格に取り扱い、不正な文字エンコーディングを検出した場合、致命的なエラーとして処理しなければならない

これらの点に注意すれば、文字エンコーディングを利用した攻撃に脆弱なアプリケーションを作っていまう可能性が低下します。データベース等で文字エンコーディングを指定できる場合、必ず利用している文字エンコーディングを指定するようにします。

最後になりますが、文字エンコーディングはできる限り統一したほうが、文字エンコーディングに関連した問題が発生し辛くなります。SJISにはほかの文字エンコーディングにないリスクがあります。UTF-8エンコーディングが特別に安全とは言えませんが、多くの言語に対応しているので、Webアプリケーションを作る場合、特に理由がなければUTF-8エンコーディングに統一するとよいでしょう。

おすすめ記事

記事・ニュース一覧