| « 入門書の書き方 | SpamメールでのWMF攻撃 » |
サニタイズと言わない
リンク: http://takagi-hiromitsu.jp/diary/20051227.html#p01
珍しくサニタイズという考え方自体が間違っているという意見を見ました。
私もサニタイズと言う考え方はNagative Security(禁止事項を定義する考え方)からの発想なので、Positive Security(許可する事項を定義する考え方)でプログラムを作るべきと考えていますし、あちらこちらで言っています。この高木さんのブログのでは、デフォルトのコーディングスタイルではサニタイズを考えなくても良いようにする事、と意見されているだと思います。いちいち意識しなくても良いようなスタイルの方が間違いが少なくなるので良いことだと思います。
# Googleで調べるとNagative/Positive Securityの方がよく利用され
# ていることが分かりますが、個人的にはNagative/Positive Security
# と言っても分かりづらい気がします。Reactive/Proactive Security
# と (受動的/能動的セキュリティ)言った方が分かりやすい気がする
# のでこっちを使っています。
Reactive/Proactiveなセキュリティと考えるとコーディングスタイルの変更によるセキュリティ確保はProactiveなセキュリティ対策なので実践していきたいものです。
ところで、常々感じているのは多くのプログラムで「サニタイズ」という概念のおかげで入力値の確認が疎かになっているのではないでしょうか?セキュアなコードでは入力値が
-期待する形式であるか?
-期待する範囲であるか?
確認することが重要です。期待する形式である、ということは文字の種類等だけではなく、selectやradioフィールドの値であるならプログラムで設定した入力値であるか照合する事も含めてチェックします。selectやradioでなくてもプログラムが設定する値であるなら必ずプログラムkが設定している値であるかも確認自由形式の文字列であれば文字数やエンコーディング、数値であれば最小、最大値の範囲内であるかチェックします。もし、おかしなデータがあれば適切はログを取り、適切なエラー画面を表示します。ライブラリ化していれば別に難しい事でも手間がかかる事ではありません。手製のHTMLフォームクラスではJavaScriptとサーバサイドの両方で自動的にチェックするようになっています。
# JavaScriptでチェックしているのはフォームPOST後に
# 「形式が違います」等とエラーになるのが自分が嫌い
# だからです。
多くのプログラムで「サニタイズしようと考えた結果、セキュリティホールを作ってしまった」のは今までのセキュリティホールを見てみれば明らかです。サニタイズには語源のSanitize -(真実を曲げたりして)無害にする、と定義されている通り間違った使用例が多く見受けられます。よくあるサニタイズコードの悪い所は「ダメな部分を取り除く」だけのコードになっている事が多い点です。これでは攻撃されていても攻撃があった事さえ分かりません。攻撃者は不正な入力値を含むデータを送信してもエラーも無く処理が終了する事で、システムはReactive Securityを使用している事が分かります。ReactiveなセキュリティモデルのシステムはProactiveなセキュリティモデルより脆弱である事が多く(現実的にはReactiveセキュリティモデルのみでセキュリティを確保することは無理)、攻撃者のターゲットとして選ばれる確立も高くなります。
念のために、Reactiveなセキュリティモデルが役立たずか、という事ではありません。Reactiveなセキュリティモデルも非常に有用です。その典型的な例はIPSです。本来セキュリティホールがある場合、IPSで対処するのではなくセキュリティホール自体を修正するべきです。しかし、コードがない製品の脆弱性でベンダーがなかなか対応してくれない場合、アプリケーションの修正とテストに多くに時間が必要な場合も多くあります。こういった場合、IPSが無いとセキュリティを確保できません。最終的にはIPSでチェックしなくても良いようにシステムを変更するべきですがIPSは「つなぎ」に欠かせません。
Sanitizeという概念が混乱(?)を起こすのは入力・出力両方に同じ用語が使われていることも原因の一つではないかと考えています。「不正な入力がないようSanitizeし、....」とか「不正な文字列が無いようSanitizeを行ってからHTMLを出力し、.....」等と入力確認と適切な出力形式への変換を同じ用語で説明しています。同じ用語で2つ以上の事柄を意味すると混乱の元です。この意味でもサニタイズとは言わないようにと言う意見には賛成です。
Javaの場合は適切なタグを利用すれば自動的にHTML出力に適した形式で出力してくれますがPHPにはシステムが提供する関数にはそのような関数がありません。つい最近、webappsec MLでやりとりをしている中でOWASP Guideを書いている人(?)のメールにも書いてあったのですが「どうせPHP6はUTF-8対応で互換性の多くを失うのだから
-eche, print, printf: 自動的にHTML用に出力
-echo_raw, print_raw, printf_raw: ダイレクトに出力
のように変えた方が良い」とありました。最初は「どうかな」と思いましたがこれくらいの変更をしないと安全でないコードを駆逐することは難しいかも知れません。この変更を行えばXSS脆弱性を持つPHPコードが激減することは確かだと思います。
5 コメント
PHPのコードではhtml出力はドキュメント全部を生成してから出力するようにしています。テンプレートに利用する値は、テンプレートに適用する直前、選択的にhtml用出力に変換しています。
echo, printで部分的にHTMLを出力していれば必要な箇所でechoとecho_rawを組み合わせることも出来ますが、現在のテンプレートシステムでは無理ですね。テンプレート適用直前に処理を行っているのでXSS問題が起きるかどうかチェックするのは簡単ですが。
-echo_raw, print_raw, printf_raw: ダイレクトに出力
これを実施した場合、移行期の互換性をどう確保するのか少しだけ考えてみました。echo, printは関数ではないので関数テーブルを書き換えるモジュールも作れないですね。今の言語仕様だとecho, printはコンパイル時に処理しなければならないのでINI_SYSTEMのスイッチで変更しなければなりません。INI_SYSTEMの設定項目はホスティング環境で問題になります。仕方がないのできっぱり割り切って互換用の設定などは考えないのが良いかな?