アプリケーションは「動けばよい」のではなく、「正しく動作」しなければなりません。システム全体の安全性を確保するためには可能な限り未知の脆弱性にも備えなければなりません。未知の脆弱性からシステムを保護するには、可能な限り厳密な入力の検証が効果的です。
Webシステムのサーバ側のシステムはWebサイト管理者側で管理可能ですが、それでも新しい脆弱性が次々に発見されています。ブラウザやブラウザのプラグインの脆弱性はWebサイト管理者側からどうすることもできない場合がほとんどです。しかし、可能な限り厳しい入力の検証を行えば、サーバ側、クライアント側に脆弱性があった場合でも回避できるケースも少なくありません。
例えば、HTTPヘッダで文字エンコーディングを指定していても、テキストから勝手に文字エンコーディングを推測して別の文字エンコーディングとして認識してしまうブラウザもあります。データベースによっては数値型のフィールドに文字列が保存できるデータベースもあります。数値以外ならデータ挿入時にエラーになるので安全である、と勘違いし「数値を思っていた値」を保存するとSQLインジェクションだけでなく恒久的なスクリプトインジェクションを許してしまう場合があります。
壊れた文字エンコーディングを利用した攻撃は、SQL文、XML文書などに対して利用できます。仮にデータベースサーバやXML文書を処理するライブラリなどが文字エンコーディングベースの攻撃に脆弱であっても、入力文字列のエンコーディングを厳格にチェックしていれば攻撃が行えない場合がほとんどです。
入力文字列は利用している文字エンコーディング、文字、文字列の長さ、形式をできる限り厳しい条件でチェックします。これによりコード全体の安全性検証も容易になり、予想していない脆弱性にも対処できる可能性が増加します。
例えば、文字エンコーディングベースのSQLインジェクション/スクリプトインジェクション/XMLインジェクションや、PHP5.2.5で修正されたhtmlentities/htmlspecialchars関数の壊れたUTF-8エンコーディングの脆弱性などは、文字エンコーディングが正しいか検証し、不正な場合はスクリプトの実行を停止していれば問題を回避できます(SJISの場合、エスケープ処理の方法により文字エンコーディングチェックを行っていても攻撃可能になります)。
すべての入力値は可能な限り厳しい条件で検証するのは、セキュアなシステム構築の原則です。
対策のまとめ
- 入力チェック(バリデーション)は最初の処理として行う
- すべてのバリデーションは必ずサーバ側で行う
- バリデーション条件は可能な限り厳しい条件を設定する
- 文字エンコーディングが正しいか必ずチェックする
- バリデーションエラーを修正(不正文字などを削除するサニタイズ処理)しない
- バリデーションエラーは必ずエラーとして処理する(不正な文字を削除する、などのサニタイズ処理を行わない)
- 明らかなセキュリティ上の問題はセキュリティエラーとして処理する(スクリプトの実行を停止する)