smartyのエスケープについて見直す

SmartyではPHPの値を出力するとき、デフォルトではエスケープされていないので、 XSS対策として、明示的にエスケープしなければなりません。

XSS対策としての正しくエスケープを行うには、内部でどのような動きをしているのか把握する必要があるので、 見直していきます。

以下の環境を使って見直す

  • PHP7.3
  • Smarty3.1.36

ドキュメントを確認してみる

大まかに解説が載っているが、javascript など抜けているのもある https://www.smarty.net/docs/ja/language.modifier.escape.tpl

コードを確認してみる

こちらを読んでいけばわかりそう。 https://github.com/smarty-php/smarty/blob/v3.1.36/libs/plugins/modifiercompiler.escape.php

エスケープ処理を見ていく

html

  • デフォルト
  • htmlspecialcharsをかけ & " ' < >エスケープする
    • オプションは、ENT_QUOTES 固定
    • smartyで指定された文字コードを指定
    • htmlspecialcharsの第四引数、double_encodeのオン・オフが選べる

https://github.com/smarty-php/smarty/blob/v3.1.36/libs/plugins/modifiercompiler.escape.php#L46-L54

htmlall

  • 適用可能な文字を全て HTML エンティティに変換する
    • マルチバイトもHTML エンティティに変換するため、mb_stringが有効なときは、htmlspecialcharsをした上 で、mb_convert_encodingしている。

https://github.com/smarty-php/smarty/blob/v3.1.36/libs/plugins/modifiercompiler.escape.php#L56-L81

url

  • rawurlencodeを行う

https://github.com/smarty-php/smarty/blob/v3.1.36/libs/plugins/modifiercompiler.escape.php#L84

urlpathinfo

  • rawurlencodeを行う
    • ただし、%2F/ に戻すようにしている

https://github.com/smarty-php/smarty/blob/v3.1.36/libs/plugins/modifiercompiler.escape.php#L86

javascript

https://github.com/smarty-php/smarty/blob/v3.1.36/libs/plugins/modifiercompiler.escape.php#L94

XSSの対応

HTML要素、属性値、リンクに値を入れるとき

escape:html を使う

<h1>{$hoge|escape:html}</h1>
<input type="text" name="hoge" value="{$huga|escape:html}" />
※属性値はダブルクォートで囲ってあること
<a href="{$hoge|escape:html}">リンク<a>
※別途スキーマのバリデーションは行うこと

URLのパラメータに値をいれるとき

escape:'url', escape:'urlpathinfo' を使う

<a href="http://localhost:8080/index.php?hoge={$hoge|escape:'url'}"
<a href="http://localhost:8080/{$hoge|escape:'urlpathinfo'}"

JavaScriptの文字列に値をいれるとき

function hoge(){
    var = "{$hoge|escape: 'javascript'}";
}
※ そもそも、JavaScript内に動的に値を埋め込まないのがベスト

イベントハンドラの場合は、+αでHTMLのエスケープをする

<body onload="console.log('{$hoge|escape: 'javascript'|escape: 'html'}');">

参考

体系的に学ぶ 安全なWebアプリケーションの作り方 第2版