Smarty3でのエスケープ漏れの防ぎ方

記念すべきblog第1回目は、最初から技術話です。このblogの方向性が見えようというものですね。

HTML出力でのエスケープを1つ1つやっていると、エスケープ漏れがセキュリティホールになるため危険です。デフォルトでエスケープされ、指定時のみエスケープしないようにするのが漏れがなくなり安全です。

Smarty3ではそのようなやり方が可能になりました。

エスケープする:{$xss_string}
エスケープしない:{$html_string nofilter}

variableフィルタを使うことでこれが可能になります。

function variablefilter_escape($value, $smarty)
{
return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
}

$smarty->registerFilter('variable', 'variablefilter_escape');

マニュアル:http://www.smarty.net/docs/ja/api.register.filter.tpl

マニュアルにはvariableフィルタの詳細については書かれていないのですが、{}で囲まれた部分を出力する際にこのフィルタが呼ばれます。フィルタを通したくない場合にはnofilterを指定することでフィルタが使われなくなります。

悩ましいのが「HTMLはエスケープしたいけど改行は<br />にしたい」という場合です。「{$xss_string|nl2br nofilter}」では全体がエスケープされずxssの危険があります。「$xss_stringをエスケープしたのちにnl2brをしてnofilter」が正解ですが、次のようになります。

{{$xss_string}|nl2br nofiler}

直観的ではないのですが、{}の単位でエスケープされるので、このような表記が可能になります。