【入門編】クロスサイトスクリプティング(XSS)の分類とDOMベースXSSの仕組み – アプリケーションセキュリティ & 安全な開発防御ガイド

「あなたのサイトが乗っ取られる?」XSSの正体と、今日からできる防犯対策

こんにちは。セキュリティの現場で日々、泥臭いインシデントと向き合っているエンジニアです。

皆さんは「XSS(クロスサイトスクリプティング)」という言葉を聞いて、どんなイメージを持ちますか? 教科書には「悪意のあるスクリプトを注入する」なんて書かれていますが、これだと少し硬いですよね。

今日は、私たちのWebサイトを「一軒の家」に見立てて、泥棒(攻撃者)がどうやって入り込み、何をしていくのか、そして私たちがどうやって鍵をかけるべきか、一緒に紐解いていきましょう。

—

XSSって結局なに?:泥棒の侵入経路を知ろう

XSSは、一言で言えば「あなたのWebサイトを『信頼できる場所』と勘違いさせ、ユーザーのブラウザ上で勝手に悪事を働かせる攻撃」です。

大きく分けて3つのパターンがあります。家の防犯に例えてみましょう。

1. 反射型XSS(通りすがりの置き引き)

ユーザーが検索窓などに打ち込んだ文字が、そのまま画面に表示される仕組みを利用します。「検索結果:『』は見つかりませんでした」というふうに、入力した内容がそのまま画面に「反射」して返ってくるのを利用する手口です。URLに悪意のあるコードを仕込んで誰かに踏ませる、まさに「置き引き」のような罠です。

2. 蓄積型XSS(留守番電話に毒を仕込む)

掲示板やプロフィール欄など、一度書き込んだ内容がサーバーに保存され、後から他のユーザーが見る場所で発生します。誰かが掲示板に悪意あるコードを書き込むと、そこを見た人全員が被害に遭います。家で言えば、共有の伝言板に「毒入りの手紙」を貼っておくような、極めて危険な状態です。

3. DOMベースXSS(家の鍵穴をすり替える)

これが今回深掘りしたい「最新の曲者」です。サーバーを介さず、ブラウザの中だけで完結するのが特徴です。
例えば、URLの末尾(#以降など)にある情報をJavaScriptで読み取って画面に表示するようなサイトだと、サーバー側では攻撃に気づけません。ブラウザの「中身(DOM)」が書き換えられてしまうため、サーバーという玄関を通らずに、勝手に家の鍵穴をすり替えられるようなイメージです。

—

DOMベースXSSの「盲点」:JavaScriptの甘い罠

DOMベースXSSが厄介なのは、「サーバー側では何も悪いことが起きていないように見える」点です。

例えば、以下のようなJavaScriptがあったとします。

// URLのパラメータから名前を取得して表示するコード
const params = new URLSearchParams(window.location.search);
const name = params.get(“name”);

// ここが危険!入力値をそのままHTMLとして書き込んでしまう
document.getElementById(“welcome-msg”).innerHTML = “ようこそ、” + name + “さん!”;

もし攻撃者がURLを ?name= のように書き換えたらどうなるでしょう? ブラウザは「あ、タグを表示しなきゃ!」と頑張りますが、画像が存在しないのでエラー(onerror)が発生し、その瞬間に攻撃者のプログラムが実行されてしまいます。

対策の基本は「innerHTMLを使わないこと」です。

// 安全な書き方:テキストとしてのみ扱う
document.getElementById(“welcome-msg”).textContent = “ようこそ、” + name + “さん!”;

textContent を使えば、たとえ攻撃者がタグを送り込んでも、ただの「文字」として表示されるだけです。泥棒が壁に落書きしようとしても、ただの紙を貼るしかできないのと同じですね。

—

現場で役立つ「最強の防犯装置」:セキュリティヘッダー

コードを直すのと並行して、Webサーバー側で「門番」を立たせることも重要です。それがContent Security Policy (CSP) です。

サーバーからブラウザに向けて、「うちのサイトでは、こういうスクリプトしか動かしてはいけないよ!」という命令を出す設定です。

HTTPレスポンスヘッダーの例
Content-Security-Policy: default-src ‘self’; script-src ‘self’;

  • default-src ‘self’: 基本的に、自分のサイト(ドメイン)にあるもの以外は読み込ませない。
  • script-src ‘self’: 外部からの怪しいスクリプト実行を禁止する。

これを入れておくだけで、万が一どこかに脆弱性が残っていても、攻撃者が用意した外部の悪意あるサーバーへの通信をブラウザが遮断してくれます。

—

最後に:完璧なセキュリティなんてない

セキュリティの世界には「絶対」はありません。泥棒も常に新しい手口を考えています。

でも、「ユーザーから受け取ったものを、そのまま画面に出さない(出力エスケープ)」「怪しい外部スクリプトを許可しない(CSP)」という二つの鍵をかけるだけで、被害のリスクは劇的に下がります。

まずは自分の書いているコードで innerHTML が使われていないか、検索してみてください。それだけで、あなたはもう「セキュリティ意識の高いエンジニア」の第一歩を踏み出しています。

一歩ずつ、丁寧に。これからも一緒に学んでいきましょう!

コメント

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