「サニタイジング言うなキャンペーン」を考える

27日のひろみちゅ日記が面白い。論点が多岐にわたりながらそれぞれ微妙につながっていて*1色々考えさせられた。以下色々考えたメモ。僕はWebプログラミングについてはほとんど素人なので的はずれなことも書くかもしれない。よってツッコミ歓迎。

開発者の視点とは

をまとめると、「悪い入力」とはなにかを考えてそれを削除するという発想(攻撃者の視点)ではなく、「正しい出力」とは何かを考えて正しいデータのみを出力する*2という発想(開発者の視点)のプログラミングスタイルを浸透させよう、ということだと思う。

そっちが本筋で「サニタイズ」に対して応急処置もしくは保険としての意味以上のことを求めてはいけないと。

「正しい」データとは

ここで言う「正しい」というのはXMLで言う「妥当性(validity)」と同じで、形式的なもの。何か望ましくないことが起こらないような、という意味ではない。一方サニタイジングという言葉が使われる場合の「悪い入力」は「望ましくない」ことが起こるような入力というニュアンスになりがちだが、ここで言う「正しい」は「悪い」の反対ではない。まず「望ましいこと」をするのに必要な最低限の値域が決まっていて、その範囲内にある入力を「正しい」と考える。

つまり、最低限の値域というのをあらかじめ決めておかなくてはならない。ちょっとデキるプログラマはほっとくと万能なコードを書こうとする性質がある。仕様変更があっても今まで書いたコードを再利用できるように。それはそれで意味のあることなので非難できない。何でも通すコードを書かれたくなければ仕様書で値域をきちんと指定するべき。

基本的に「望ましくない」ことを想定して回避するのはプログラマの仕事ではないと思う。上流工程で「正しい」入力値の値域を定義する際に考えるべきで、そうでないと何が「望ましくない」ことか定義されず、それはテストケースにも反映されない。現実にはプログラマの良心と配慮に満ちた実装に救われて「望ましくない」ことが起こらずに済んでいるシステムもいっぱいあるのかもしれないが。

データがタグ付きテキストの場合

高木氏の挙げた例ではデータがプレーンテキストなので話は簡単だ。しかしデータがタグ付きテキストの場合はどうか。掲示板やブログなど入力に制限付きでタグを許すシステムではデータ自体がタグ付きなので出力時に一律タグをエスケープするわけにはいかない。どうするか。特にHTML断片がデータになっている場合は、出力時ではなくデータ入力時に「正しさ」を検証、もしくは「正しい」値域におさまるような変換をかける必要がある。

が、タグ付きテキストの「正しさ」の検証は簡単ではない。正規表現でごにょごにょやってると漏れが出てきやすい。プログラミングの観点からは XML として妥当性検証(バリデーション)をかけるのが一番楽であり安心・確実なのだが*3、エンドユーザに妥当なXMLを書かせるのは非現実的かもしれない。

それでもせめて入力を一度 DOM のような構造化データ(タグとテキストを区別できる形のデータ)に変換してからチェックをかければかなりリスクは減るはず。テキストのままで扱うのに比べると高木氏が指摘した「../」削除の問題*4のような不具合は防げるはずだ。

データのタイプと出力先のタイプ

出力段のモジュールにとって、データの「正しさ」は、モジュールに入ってくるデータのタイプによって、また、モジュールが出力する場所のタイプによって違ってくる。HTML断片をHTML要素内容として出力するならタグをエスケープせずに出力するべきだし、プレーンテキストをHTML要素内容として出力するならタグはエスケープする必要がある。また同じプレーンテキストのデータでもURLとして出力するなら(つまり出力先が a 要素の href 属性値だったりする時)別の形のエスケープが必要になる。

ところが普通のプログラミング言語ではデータについても出力先についても上に挙げた意味での型というものがなく、全部単なるテキスト処理として扱うしかないことが多い。高木氏の記事にトラックバックしている小川氏の記事でもこの点が指摘されているが、それに対する対策というのがなかなか直観的かつスマートにはならないのが辛い。

サーバーサイドスクリプティング言語で、テンプレートのどこにどんな型のデータが埋め込まれているかを認識して、データの型と出力先の型に合わせた適切な変換を自動的にやってくれるのがあったらいいのだけど。

*1:ある意味まとまりがないともいえるがまとめる前の段階の論考だろうからしょうがないか。

*2:必ず正しくなるような変換をかける、もしくは正しくないデータはエラーとして出力しない。

*3:設計段階でスキーマが書かれているものとする。そうでなければ楽かどうかは人による。

*4:こういうバグって一般に何ていうんでしょう? 僕は勝手に「ダルマ落とし現象」とか呼んでますが。