はじめに
クロスサイトスクリプティング (XSS) 攻撃について学習する備忘録です。
改訂履歴
- 2026/09/15 : 初版公開。
本文
1. 概要
クロスサイトスクリプティング (Cross-Site Scripting / XSS) 攻撃は、Web アプリケーションがユーザーから受け取ったデータを適切に処理・出力しないことによって、攻撃者が用意したスクリプトを被害者のブラウザ上で実行させる脆弱性です。
XSS の本質は、Web アプリケーションが「データ」として扱うべき入力を、HTML や JavaScript 等の「コード」として解釈される状態でブラウザに渡してしまうことにあります。XSS が成立すると、攻撃者が被害者のブラウザ上で任意の JavaScript を実行できる可能性があります。その結果、Web ページの改ざん、ユーザーの操作を誘導する画面の表示、ブラウザ上で利用可能な情報の窃取等に繋がる場合があります。
対策としては、出力コンテキストに応じた適切なエスケープを行うこと、危険な HTML を生成・挿入する API の使用を避けること、必要に応じて Content Security Policy (CSP) を利用すること等が挙げられます。
2. 類型
OWASP では、XSS を主に次の 3 種類に分類しています。
| 種類 | 発生場所 | 処理 | 特徴 |
|---|---|---|---|
| 反射型 (Reflected XSS) | サーバー側 | 入力値をレスポンスへ反映する処理 | 入力値がリクエストからレスポンスへ直接反映される。 |
| 格納型 (Stored XSS) | サーバー側 | 入力値を DB 等へ保存する処理 | 攻撃コードがサーバー側に保存され、別のユーザーへ配信される。 |
| DOM ベース (DOM Based XSS) | クライアント側 | JavaScript による DOM 操作 | サーバーのレスポンス生成を介さず、ブラウザ上の JavaScript によって XSS が成立する。 |
2-1. 反射型
反射型 XSS は、攻撃者から送信された入力値がサーバー側でレスポンスに反映され、そのレスポンスを被害者のブラウザが解釈することで発生します。典型的には、検索キーワードや URL のパラメータ等を Web ページへ表示する処理に、適切な出力エンコーディングが行われていない場合に発生します。
https://example.com/search?q=<script>alert(1)</script>
攻撃者がこのような細工した URL を被害者に開かせると、URL に含まれる入力値が Web ページに反映され、被害者のブラウザ上でスクリプト <script>alert(1)</script> が実行されます。入力値がサーバーに保存されず、リクエストに含まれた入力値がレスポンスに反映されることから、反射型または非持続型とも呼ばれます。
現代の一般的なライブラリでは、デフォルトで XSS 対策が施されているため、この単純な例は成立しないはずです。
2-2. 格納型
格納型 XSS は、攻撃者の入力した内容が DB 等に保存され、その保存された内容が別のユーザーへのレスポンスに含まれることで発生します。例えば、掲示板の投稿、コメント、プロフィール情報等を適切に無害化しないで保存し、その内容を HTML として出力する場合が該当します。攻撃者の入力した内容がサーバー側に保存されるため、攻撃者が直接 URL を開かせなくても、対象ページを閲覧したユーザーに対して攻撃が成立します。この性質から格納型または持続型とも呼ばれます。
2-3. DOM ベース
DOM ベース XSS は、サーバーが危険な HTML を生成するのではなく、クライアント側の JavaScript が外部から取得したデータを DOM へ挿入することで発生する XSS です。
DOM (Document Object Model) とは、HTML や XML 等の文書をオブジェクトのツリー構造として表現し、JavaScript から操作できるようにするモデルです。ブラウザ毎に異なっていた文書操作の仕様を統一するため、W3C によって 1998 年に標準化されました。
反射型 XSS では、攻撃者から送信された入力値がサーバー側でレスポンスに反映されます。一方、DOM ベース XSS では、入力値がサーバーを経由せず、ブラウザ上の JavaScript によって直接 DOM に反映されることがあります。
例えば、次のような JavaScript があるとします。
<script>
const message = location.hash.substring(1);
document.getElementById("message").innerHTML = message;
</script>
このページに次のような URL でアクセスします。
https://example.com/#<img src=x onerror=alert(1)>
ブラウザ上の JavaScript が URL のフラグメントから値を取得し、それを innerHTML に渡します。その結果、入力値が HTML として解釈され、XSS が発生する可能性があります。ここで重要なのは、URL の # 以降のフラグメントは通常サーバーへ送信されないという点です。そのため、サーバー側のレスポンスに攻撃者の入力値が含まれていなくても、クライアント側の JavaScript の処理によって XSS が発生する場合があります。
URLの # 以降は「フラグメント」や「アンカー」と呼ばれ、ページ内の位置指定等に使われます。フラグメントは Web 標準上、HTTPリクエストの対象には含まれず、サーバーには送信されません。
このため、DOM ベース XSS の対策では、サーバー側の入力検証だけでは不十分であり、クライアント側 JavaScript におけるデータの扱いも確認する必要があります。特に、外部から取得したデータを HTML として解釈させるような DOM API の利用には注意が必要です。
3. 対策
全ての XSS に対して有効で基本となる対策は、サニタイジング(エスケープ処理)と Content Security Policy (CSP) の設定になります。
3-1. サニタイジング(エスケープ処理)
ユーザーから入力された値を HTML 等へ出力する際に、HTML のタグや特殊文字として解釈されないようにエスケープ処理を行います。例えば入力値に <script> タグが含まれていた場合、そのまま HTML として出力するのではなく、< や > 等をエスケープすることで、単なる文字列として扱わせます。
以下は主な置換文字です。
| 入力値 | 置換文字 (HTML) | 置換文字 (CSS) | 置換文字 (JavaScript) |
|---|---|---|---|
& |
& |
¥26 |
¥u0026 |
< |
< |
¥3C |
¥u003C |
> |
> |
¥3E |
¥u003E |
" |
&guot; |
¥22 |
¥", ¥u0022
|
' |
' |
¥27 |
¥', ¥u0027
|
3-2. Content Security Policy (CSP) の設定
Content Security Policy (CSP) は HTTP レスポンスヘッダの Content-Security-Policy にポリシーを設定することで、ブラウザが実行できるスクリプトや読み込めるリソースを制限する仕組みです。CSP を適切に設定することで、XSS が発生した場合でも、攻撃者が挿入したスクリプトの実行を制限できる場合があります。ただし CSP は XSS 自体を防ぐものではなく XSS が発生した場合の影響を軽減するための多層防御として利用します。
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Content-Security-Policy:
default-src 'self'; ... 明示されていないリソースは同一オリジンのみ許可。
script-src 'self' 'nonce-{RANDOM}'; ... 同一オリジンの JS と、指定 nonce を持つインライン JS のみ許可。
style-src 'self' 'nonce-{RANDOM}'; ... 同一オリジンの CSS と、指定 nonce を持つインライン CSS のみ許可。
img-src 'self' data:; ... 同一オリジンと data: の画像を許可。
font-src 'self'; ... 同一オリジンのフォントを許可。
connect-src 'self'; ... fetch、XHR、WebSocket 等の通信先を制限。
media-src 'self'; ... 同一オリジンの音声・動画を許可。
object-src 'none'; ... object、embed 等を禁止。
frame-src 'none'; ... iframe 等による外部ページの埋め込みを禁止。
frame-ancestors 'none'; ... このページを iframe 等に埋め込むことを禁止。
base-uri 'self'; ... base 要素の URL を同一オリジンに制限。
form-action 'self'; ... form の送信先を同一オリジンに制限。
manifest-src 'self'; ... Web App Manifest を同一オリジンに制限。
worker-src 'self'; ... Worker を同一オリジンに制限。
upgrade-insecure-requests; ... HTTP のリソース URL を HTTPS に変更。
3-3. DOM ベース XSS への対策
DOM ベース XSS はクライアント側の JavaScript によって発生するため、DOM 操作を行うコードについて、以下のような対策が必要です。
-
document.writeやinnerHTML等、入力値を HTML として解釈させるメソッドを使用しない。createElementやtextContent等、入力値を HTML として解釈せずに処理できる API を使用する。 - JavaScript のライブラリを最新に保つ。
- 文字列をコードとして実行する
eval()やnew Function()等を使用しない。
4. 参考
おわりに
気付きがあれば、追記します。