【実務・中級編】JavaScriptのテンプレートリテラルとXSSリスク – アプリケーションセキュリティ & 安全な開発防御ガイド

「便利だから」で済ませていないか?テンプレートリテラルが招く現代のXSSリスク

現場でコードレビューをしていると、今でも後を絶たないのが「テンプレートリテラル」の安易な使用によるXSS(クロスサイトスクリプティング)の脆弱性だ。

「バッククォートで囲んで ${variable} と書けば楽だし、可読性も高い」。確かにその通りだ。しかし、この便利さは、ブラウザにとって「どこまでがデータで、どこからが実行可能なコードなのか」という境界線を曖昧にする諸刃の剣でもある。

今日は、なぜ現代のフロントエンド開発においてテンプレートリテラルが「脆弱性の温床」になり得るのか、そしてそれをどうやって封じ込めるのかを、プロの現場の視点で解説しよう。

—

なぜテンプレートリテラルは「魔の入り口」なのか

攻撃者は常に「ブラウザがどう解釈するか」の先を読んでいる。例えば、以下のような実装を見たことはないだろうか。

// 脆弱な実装例
const username = new URLSearchParams(window.location.search).get(‘name’);
const welcomeMsg =

こんにちは、${username}さん!

;
document.getElementById(‘app’).innerHTML = welcomeMsg;

もし攻撃者が ?name= というURLを送りつけたらどうなるか? テンプレートリテラルは、変数 username の中身をそのまま文字列として埋め込んでしまう。結果、ブラウザはそれを「HTMLの一部」として解釈し、JavaScriptが実行される。

これは単なる文字列連結の延長ではない。テンプレートリテラルは改行や複雑な引用符をそのまま許容してしまうため、DOM操作の文脈においては非常に攻撃が成功しやすい環境を作ってしまうのだ。

—

実践:防御の鉄則「DOMを汚染しない」

この脆弱性を根本から叩くには、「HTML文字列を生成しない」ことが最強の防御策だ。しかし、どうしても動的なDOM構築が必要な場合、どうすべきか。

1. 推奨:textContent を使う(安全の基本)

そもそもHTMLとして解釈させる必要がない場所には、絶対に innerHTML を使わない。textContent を使えば、ブラウザは値を「単なる文字列」としてのみ扱い、HTMLタグとしての解釈を完全にブロックする。

// セキュアな実装例
const username = new URLSearchParams(window.location.search).get(‘name’);
const div = document.createElement(‘div’);
div.textContent = こんにちは、${username}さん!; // これならタグはただの文字列として表示される
document.getElementById(‘app’).appendChild(div);

2. どうしてもHTMLを埋め込みたい場合(エスケープ処理)

どうしても動的にHTMLタグを含む文字列を展開しなければならない場合は、信頼できない入力を必ず「エスケープ」する関数を通す必要がある。

/

  • 簡易的なHTMLエスケープ関数
  • 文字列中の特殊文字をHTMLエンティティに変換する

/
function escapeHTML(str) {
return str
.replace(/&/g, ‘&’)
.replace(//g, ‘>’)
.replace(/”/g, ‘”‘)
.replace(/’/g, ”’);
}

const rawInput = ““;
const safeHTML =

${escapeHTML(rawInput)}

;
// これなら が として表示され、攻撃は不発に終わる

—

バックエンドでの防御:CSP(コンテンツセキュリティポリシー)という最後の砦

フロントエンドでの対策が漏れていたとしても、システム全体で致命傷を避けるための「防波堤」を用意しておくのがプロの仕事だ。それが CSP (Content Security Policy) である。

Nginxやサーバー側のレスポンスヘッダーで、以下のポリシーを検討してほしい。

Nginxの設定例: インラインスクリプトの実行を原則禁止する
add_header Content-Security-Policy “default-src ‘self’; script-src ‘self’; object-src ‘none’;”;

  • default-src 'self': 外部からの不正なスクリプト読み込みを制限。
  • script-src 'self': インラインスクリプト(など)の実行をブラウザ側で拒否する。

これにより、万が一テンプレートリテラルから不正なタグが混入しても、ブラウザ側が「このスクリプトは許可されていない」と判断して実行をブロックしてくれる。

—

最後に:セキュリティは「性悪説」で設計せよ

現場で多くのインシデントを見てきたが、脆弱性は常に「まさかこんなところから」という場所で発生する。「ここは管理画面だから大丈夫」「社内ユーザーしか使わないから」という油断が、バックドアを開ける鍵になる。

1. 文字列連結によるHTML生成をコードベースから排除する。
2. ブラウザのDOM API(textContent, createElement)を優先する。
3. どうしても必要な場合はエスケープ関数を必ず挟む。
4. CSPで多層防御を敷く。

この4つを徹底するだけで、テンプレートリテラルに起因するXSSリスクは限りなくゼロに近づく。コードを書く際、「これはブラウザに対して、どのような命令を送っているのか?」と一瞬立ち止まる習慣をつけてほしい。その一秒の思考が、組織の信頼を守る大きな盾になるはずだ。

コメント

タイトルとURLをコピーしました