安全なテンプレートシステムはあるのか
2008年2月3日(日曜日)
安全なテンプレートシステムはあるのか
またしても「例えば、PHP」のような話で盛り上がっているようですが、それとはあんまり関係ないところに反応……「安全なWebアプリのために言語ができること (www.rubyist.net)」。
テンプレートシステムによる出力
インジェクションなどの原因となる生の文字列操作でHTMLを構築することをできるだけ避ける。
しかし、安全で苦労知らずのテンプレートシステムってあんまり見たことないのですよね。仕事で扱ったことがあるのは、
- PHP + Smarty
- Perl + Catalyst + Template-Toolkit
- Ruby + Ruby on Rails + eRuby
といったあたりですが、いずれもXSSを回避するためには気配りが必要で、一筋縄ではいかなかったりします。
たとえば eRuby の場合、
<h1><%=h @foo.title %></h1>
のように h() を通せばエスケープされます。これはシンプルで分かりやすいし、h() を書かなくて良いところにも全部 h() を書くようにすれば、わざわざエスケープなんて意識しなくても良いよね……と思うわけですが、実際やってみると、そううまくは行かないケースも多いわけです。
良くあるのが、タグを出力しなければならないケース。
<div class="comment">
<p><%=h auto_link(user_comment) %></p>
</div>
auto_link は文中の URL をリンクにするメソッドですが、上記のように書くと URL が a要素に変換された後で h を通ることになり、残念なことになってしまいます。以下のようにするのが正解です。
<div class="comment">
<p><%=auto_link h(user_comment) %></p>
</div>
この場合は auto_link だけなのでシンプルですが、独自のヘルパーメソッドがいっぱいあったりすると、だんだんゴチャゴチャしてきて頭が (時には胃が) 痛くなってきます。
要は、テンプレートが扱う値には大きく分けて 2種類があり、
- 生のデータの場合 …… エスケープして表示する
- HTML を含む (テキストはエスケープ済みの) データの場合 …… エスケープしないでそのまま表示する
メソッドにどちらを渡すのか、どちらが返ってくるのか、ということを常に意識しておかないといけないわけです。
※恐ろしいことに、Rails の url_for() などは controller で使うときと view で使うときとで性質が変わります。ドキドキですね。:-)
……というわけなのですが、個人的には、2種類のデータがどちらも同じ string 型なのがややこしさの元なのではないかと思っています。この日記を表示している hatomaru.dll は全部 DOM で処理しているので、前者は string、後者は XmlNode となっていて明確に型が違います。間違って処理する心配はなく (間違っていたらコンパイルエラーになる)、XSS 対策を考える必要がないのでとても気楽です。
他にも、DOM 型だとクラス名の出し分けが楽だったりいろいろメリットがあると思うのですが、DOM 型のテンプレートシステムは流行りませんかね。
※ちなみに hatomaru.dll は View と Controller をあんまり分離していない構造で、テンプレートシステムと呼べるようなものは実装していません。
- 「安全なテンプレートシステムはあるのか」へのコメント (5件)
- 前(古い): トリミングの妙
- 次(新しい): Winnyのファイル発信者は追跡可能