MustacheのHTMLエスケープの無効化

MustacheのHTMLエスケープの無効化

説明

テンプレートエンジンの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するだけでは元に戻りません。

参考資料