用語集 · セキュリティ
クロスサイトスクリプティング(XSS)
英語: Cross-site scripting
別名: XSS, 格納型XSS, 反射型XSS, DOMベースXSS
定義
信頼できない入力が別のユーザーのブラウザで実行可能なスクリプトとして描画され、攻撃者がそのユーザーになりすまして操作できてしまう脆弱性です。
クロスサイトスクリプティング(XSS)は、アプリケーションがあるユーザーからの入力を適切にエンコードせずにページへ埋め込み、ブラウザがそれをテキストではなく HTML や JavaScript として扱ってしまうときに発生します。スクリプトは脆弱なサイト上で被害者のセッションのまま実行され、ページのデータを読み取ったり、ユーザーとしてリクエストを送ったり、表示内容を書き換えたりできます。OWASP Top 10 2021 では A03 インジェクションに分類されています。
3 つの種類
- 格納型(Stored)。 ペイロードが保存され(コメント、プロフィール名、サポートチケットなど)、それを閲覧するすべての人に配信されます。通常、最も深刻です。
- 反射型(Reflected)。 ペイロードはリクエストに含まれ(多くは検索語などの URL パラメーター)、そのままレスポンスに返されます。
- DOM ベース。 クライアント側の JavaScript が攻撃者の制御するデータ(たとえば
location.hash)を読み取り、innerHTMLのような安全でないシンクを使ってページに書き込みます。
テスターが確認すること
後で表示されるすべてのフィールド(自分、他のユーザー、バックオフィスの管理者に表示されるもの)に無害なマーカーを入力し、テキストとして返ってくるか、有効なマークアップとして返ってくるかを確認します。以下は Playwright での自動チェックの例です(許可されたテストでのみ使用してください)。
import { test, expect } from '@playwright/test';
test('comment body is rendered as text, not HTML', async ({ page }) => {
const probe = '<img src=x onerror="window.__xssProbe=1">';
await page.goto('/posts/1');
await page.getByLabel('Comment').fill(probe);
await page.getByRole('button', { name: 'Post comment' }).click();
// Escaped output shows the literal characters on screen
await expect(page.getByText(probe)).toBeVisible();
// and the handler never ran
expect(await page.evaluate(() => (window as any).__xssProbe)).toBeUndefined();
});
単純な HTML 以外の出力コンテキストも確認してください。属性の中の値、インラインスクリプトの中、URL(javascript: リンク)、リッチテキストエディターなどです。それぞれ必要なエンコード方法が異なります。
検証すべき防御策
- デフォルトでの出力エンコード。最近のフレームワーク(React、Angular、Vue)はテキストを自動的にエスケープします。
dangerouslySetInnerHTML、v-html、innerHTMLのような抜け道が使われていないか探します。 - マークアップを本当に受け付ける機能での HTML サニタイズ。
- 第 2 の防御層として、インラインスクリプトをブロックする Content Security Policy ヘッダー。
HttpOnlyのセッション Cookie。XSS が成功しても、セッション Cookie を簡単には読み取れないようにします。
自分が所有していない、または書面でテストの許可を得ていないシステムでは、決してテストしないでください。