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をかけ
& " ' < >
をエスケープする
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
\ " '
改行</
を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内に動的に値を埋め込まないのがベスト
<body onload="console.log('{$hoge|escape: 'javascript'|escape: 'html'}');">