説明
テンプレートエンジンのHTMLエスケープ関数を、入力をそのまま返す関数に置き換えると、特殊文字が自動でエスケープされません。Mustache.jsでMustache.escapeをこのように上書きすると、攻撃者の入力がHTMLとして挿入され、クロスサイトスクリプティング(XSS)につながる可能性があります。
想定される影響
- 挿入されたスクリプトが利用者のブラウザーで動作するおそれがあります。
- スクリプトが読み取れるCookieやセッション情報などが盗まれる可能性があります。
- 表示内容を改ざんされ、サービスへの信頼が損なわれるおそれがあります。
対処方法
- HTMLのテキスト位置に値を挿入するときは、テンプレートの標準のエスケープを維持してください。
- 入力をそのまま返す関数で
Mustache.escapeを上書きしないでください。 - URL、JavaScript、CSSなどは、実際の出力先の文脈に合った検証とエンコードを行ってください。HTMLエスケープだけですべての文脈を保護できるわけではありません。
例
変更前
javascript
const Mustache = require('mustache');
// BAD: 入力をそのまま返すようHTMLエスケープ関数を上書き
Mustache.escape = function(text) {
return text;
};
const unsafeTemplate = '<div>{{userInput}}</div>';
const html = Mustache.render(unsafeTemplate, { userInput: req.query.text });
変更後
javascript
const Mustache = require('mustache');
// GOOD: Mustacheの標準のエスケープを維持
const safeTemplate = '<div>{{userInput}}</div>';
const html = Mustache.render(safeTemplate, { userInput: req.query.text });
変更前は入力をエスケープせずにページへ挿入します。変更後は、このHTMLテキスト位置に入る特殊文字をエスケープします。両者は別々の実行を想定しています。一度上書きしたグローバル関数は、再度requireするだけでは元に戻りません。