Diary?

2009-12-16
Wed

(23:33)

さて、ここで適当な HTML テンプレートエンジンを考えてみる。とりあえず文法は Smarty っぽくこんな感じで。

<p><a href="{$url}">{$text}</a></p>

ここでテンプレートのプレースホルダーはすべて自動的に HTML 特殊文字をエスケープするものとする。それでも url の値がソーシャルブックマークなど、ユーザの投稿によるものだとすると、ここに javascript:alert("fuck you") とか入力されると、出力は以下のようになる。

<p><a href="javascript:alert(&quot;fuck you&quot;)">...</a></p>

勿論これは入力時に validator で弾くべきものなのだが、とりあえず以下のような仕様のフィルターを噛ませるとする。

  • スキームが http or https は受け付ける
  • 同一サイト内へのリンクも受け付ける
  • それ以外は全部弾いて変わりにエラーメッセージを出力する

これを validate_link フィルターと呼ぶことにすると、先のテンプレートは次のように記述できる。

<p><a href="{$url|validate_link}">{$text}</a></p>

手間はかかるが、こちらの方が安全ではある。問題はその手間及び確認コストで、サイト内で使われるあらゆるテンプレートを目視で確認して適切なエスケープが行われているのかチェックするのはぶっちゃけ無理、どう考えても漏れが出る。そして

  • 入力値の検証に穴があって
  • 出力値のエスケープに冒頭のような穴がある

というケースが発生すると、当然これは脆弱性に繋がりうる。

じゃあこの問題はどうするべきなのかだが、ここでテンプレート言語は HTML への値埋め込みなので、普通に HTML 文書として解析可能だ。つまり、 href や src などのいたずらされるとマズい属性の値がテンプレートのプレースホルダーかどうかはわかるはず。なので理屈の上ではテンプレートを静的に解析して単なる特殊文字のエスケープ以外の処理が必要かどうかチェックするプログラムを書くのは不可能ではない。

……そう、不可能ではない。不可能ではないんだが、複数のテンプレート言語をサポートすると、ある属性の値がプレースホルダーかどうか判定するのがやや厳しい。一応、個々のテンプレート言語の構文解析器を工夫して作ればどうにかなりそうではあるが。でもこれどんだけやる価値があるんだろうか。何よりこういうのは言い出したらキリがないし。

Creative Commons
この怪文書はクリエイティブ・コモンズ・ライセンスの元でライセンスされています。引用した文章など Kuwata Chikara に著作権のないものについては、それらの著作権保持者に帰属します。