入力値検証の話

Webアプリケーションのセキュリティ対策としての入力値検証について議論されています。

そろそろ入力値検証に関して一言いっとくか: Webアプリケーション脆弱性対策としての入力値検証について - 徳丸浩の日記(2007-09-05)

思ったことをいくつか書きます。

  • 徳丸さんの日記は、ユーザがテキストボックスなどで自由に値を入力できる住所などのデータを主に対象としたものだと思う。
  • ただ、ユーザの自由な入力を起源としないデータも存在する(ここでは「システム起源のデータ」と呼ぶ)。
    • hidden、リンクURLに埋め込まれているGETパラメータ、Cookieなどには、この手のデータが入ることが多い。
  • システム起源のデータの多くは、ある型に従うことが期待されるもので、原則的に入力値検証をすべきもの(BMPの「ピクセルあたりビット数」と同じような感覚)。
  • システム起源のデータも、エスケープさえすればインジェクション系の問題を生じない場合が多い。ただ、エスケープ方法が存在しない文脈で使用する場合や、エスケープが困難なため、セキュリティ対策としての入力値検証が必要な場合がある(例えば以下)。
  • 入力値検証がセキュリティ上の理由で必須となるようなデータは、なるべくクライアント側に保存しない方がよい。
    • 直接的なクライアント側への保存を避けるために、データをコード化する方法がある。例えば、filename=xxx.txt ではなく、filename=1 のようなコードを受け取り、サーバ側の「1⇒xxx.txt」というような対応付け表を検索して得られる値をsysopenなどに使用する。対応付け表はDBや設定ファイルに入れても、ハードコードしてもよい(信頼境界内にありさえすれば、対応付け表から得られる値を検証する必要はない)。
    • 同じような理屈で、サーバ側のセッション変数にシステム起源のデータを入れておくことが有効な状況もあるだろう。
    • MACで第三者による改竄を防ぐ方法もある。データを受取る側がMACを含むデータ生成者を完全に信頼するならば、MACの整合性検証をパスしたfilenameを、検証せずにsysopenに入れることができる。
    • 対応付け表は、データのバリエーションが多く、またその変化の頻度が高い場合、運用コストの高い手法になる。実際のところは、入力値検証が必要なデータをクライアント側から受取るのが現実的な場合はある。
  • システム起源のデータには、システム処理(実装)の都合でのみ存在し、業務要件定義のレイヤでは存在すら意識されないものもある。そのようなデータの入力値検証は、業務要件ではなく、システムやセキュリティの要請に基づくものといえないか。
  • 住所欄や掲示板投稿文など、長さ以外は完全に自由入力な業務系データであっても、文字列として扱う以上は、文字エンコードの妥当性の観点での検証は必要になる。
    • 機種依存文字や携帯絵文字の受入を制御したり、不正な文字断片などを挿入されることを防ぐ目的で。
    • この辺は業務要件としての入力値検証と位置付けられるかもしれない(業務要件を定義する際に、システムが受け入れる文字についての規定が漏れることはあるけれども)。
    • アプリより下位のレイヤが自動的に文字エンコードを「正規化」することもある(入力データ内の文字が、ユーザに何の断りも無く「?」になって迷惑な場合もある)。

徳丸さんは「上記は大まかな議論であって、もちろん例外はありえる」と書かれています。私は主にその「例外」の部分について書いてみたつもりです。