【入門編】DOMベースXSSの発生メカニズムとクライアントサイドの脆弱性 – アプリケーションセキュリティ & 安全な開発防御ガイド

サーバーを通らない「透明な侵入者」?DOMベースXSSの正体と防犯術

こんにちは!セキュリティの現場で日々、複雑な攻撃と向き合っているエンジニアです。

今日は、多くの開発者が「サーバーを通っていないから大丈夫だろう」と油断してしまう、DOMベースXSS(クロスサイトスクリプティング)についてお話しします。これ、実は現代のWebアプリ開発において、非常に巧妙で厄介な「見えない泥棒」なんです。

小難しい専門用語はなるべく控えめに、私たちの日常にある「防犯」に例えて、一緒に紐解いていきましょう。

—

1. DOMベースXSSって、結局どんな「泥棒」なの?

一般的なXSSは、サーバーに悪意のあるコードが保存され、それがブラウザに送られてくる「外からの侵入」です。しかし、DOMベースXSSは違います。

イメージしてください。あなたの家には厳重なセキュリティゲート(サーバー)がありますが、「家の玄関を通らずに、壁の隙間(ブラウザの機能)から勝手に部屋に入り込んでくる泥棒」がいたらどうでしょう?

ブラウザ上で動くJavaScriptが、URLの一部(例えば location.hash など)を「深く考えずにそのまま画面に表示してしまう」とき、その隙間が生まれます。

例えばこんなコード…(危険な例)

// URLの # 以降をそのままページ内に書き出してしまう危険な処理
const hash = location.hash.substring(1);
document.getElementById(‘welcome-message’).innerHTML = “こんにちは、” + hash + “さん!”;

このコードだと、URLの末尾に のような罠を仕込まれると、ブラウザは「ああ、これはただの名前だな」と信じ込んでしまい、悪意あるプログラムを実行してしまいます。これがDOMベースXSSのメカニズムです。

—

2. 「鍵」の掛け方:防御の基本原則

この泥棒を防ぐには、「ブラウザに渡すものは、すべて疑え」という原則を徹底することです。

対策①:innerHTMLは使わない(「窓」を塞ぐ)

innerHTML は、渡された文字列を「ただの文字」ではなく「HTMLの構造」として解釈しようとします。これが最大の間違いです。代わりに、文字として安全に扱う textContent を使いましょう。

// 安全な書き方:これならタグを書いても「ただの文字」として表示されるだけです
const hash = location.hash.substring(1);
document.getElementById(‘welcome-message’).textContent = “こんにちは、” + hash + “さん!”;

これだけで、泥棒が窓から入ってきても「壁紙に落書き」するくらいのことしかできなくなります。

—

3. 「防犯カメラ」と「警備システム」:CSPの導入

コードの書き換えが難しい場合や、二重の防犯対策として強力なのがCSP(Content Security Policy)です。これは、Webサイトが「どのスクリプトを信頼するか」をブラウザに伝えるための防犯システムです。

サーバーのレスポンスヘッダーに、以下のような設定を追加してみてください。

Content-Security-Policy: default-src ‘self’; script-src ‘self’; object-src ‘none’;

  • default-src 'self': 基本的に、自分のサイト以外から持ってきたデータは信用しません。
  • script-src 'self': 外部の怪しいスクリプトの実行をブロックします。
  • object-src 'none': 悪用されやすいプラグインの機能を完全にオフにします。

これを設定しておくと、仮にコードに隙間があっても、ブラウザが「おっと、このスクリプトは許可リストにないぞ!」と察知して、実行を止めてくれます。

—

4. 最後に:セキュリティは「終わりのない旅」

DOMベースXSSを防ぐためのポイントをまとめます。

1. URLなどの外部入力は、決して信頼してそのまま出力しない。
2. innerHTML や document.write は極力避け、textContent を使う。
3. CSPを導入し、ブラウザという「警備員」を雇う。

セキュリティと聞くと身構えてしまうかもしれませんが、結局のところ「自分の書いたコードが、誰に、どう悪用される可能性があるか」を想像する力、これに尽きます。

今日からあなたのコードでも、location.hash や location.search を扱っている場所がないか、ぜひチェックしてみてください。一歩ずつの積み重ねが、あなたの開発するサービスを、そしてユーザーを守る一番の盾になります。

それでは、また次の現場でお会いしましょう!応援しています!

コメント

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