HTMLテンプレート文字列でのクロスサイトスクリプティング

HTMLテンプレート文字列でのクロスサイトスクリプティング

説明

ユーザー入力を適切にエンコードせずHTMLテンプレート文字列へ挿入すると、クロスサイトスクリプティング(XSS)が発生するおそれがあります。攻撃者が指定したHTMLやスクリプトが他のユーザーのブラウザーで動作し、情報漏えいやセッションの乗っ取りにつながる可能性があります。

想定される影響

  • スクリプトが読み取れるCookie、セッショントークン、入力情報が盗まれるおそれがあります。
  • 挿入されたHTMLやスクリプトにより、表示や動作を改ざんされたり、フィッシング画面を表示されたりする可能性があります。

対処方法

  • HTML本文へテキストを挿入するときは、その文脈に合うHTMLエンコードか、テンプレートの自動エスケープを使ってください。
  • マークアップが不要なら、innerHTML ではなく textContent を使ってください。setAttribute は固定された非実行属性にだけ使い、URLのスキームと宛先は別途検証してください。
  • HTMLマークアップを許可する場合は、DOMPurifyなどのHTMLサニタイザーでタグと属性を制限してください。サニタイズはテキストのエンコードとは異なります。通常のHTMLエスケープをJavaScriptやCSSの文脈に流用しないでください。

例

変更前

javascript
const userInput = '<img src="x" onerror="alert(1)">'; // 悪意のある入力
const message = `<div>${userInput}</div>`;
document.body.innerHTML = message;

変更後

javascript
function escapeHtml(str) {
  return str.replace(/[&<>'"]/g, function (c) {
    return {
      "&": "&amp;",
      "<": "&lt;",
      ">": "&gt;",
      "'": "&#39;",
      '"': "&quot;",
    }[c];
  });
}
const userInput = '<img src="x" onerror="alert(1)">'; // 悪意のある入力
const message = `<div>${escapeHtml(userInput)}</div>`;
document.body.innerHTML = message;

解説:

  • 変更前: userInput のマークアップをHTMLへ直接挿入するため、ブラウザーで実行されるおそれがあります。
  • 変更後: この例のHTML本文に合わせて escapeHtml でエンコードし、入力されたタグをテキストとして表示します。

参考資料