
オープンリダイレクト診断
オープンリダイレクトは、正規サイトの信頼性を悪用してユーザーを攻撃者のサイトに誘導する脆弱性です。 フィッシング攻撃、OAuth認証の乗っ取り、マルウェア配布などの攻撃経路として悪用されます。
チェック項目
4つの検査項目
URLパラメータベースのリダイレクト検出
redirect=, url=, next=, return_to=, goto= などのパラメータを自動検出し、外部ドメインへのリダイレクトが可能かテストします。
?redirect=?url=?next=?return_to=?goto=?continue=?dest=?target=外部ドメインへの無制限リダイレクト
リダイレクト先のドメイン検証が行われているかを確認。攻撃者が任意の外部URLにユーザーを誘導できるかテストします。
https://evil.com//evil.comhttps://evil.com%00.example.comhttps://example.com@evil.comリダイレクトチェーンの追跡
複数回のリダイレクトを追跡し、最終的な遷移先を確認。正規サイト経由で攻撃サイトへ誘導する多段リダイレクトを検出します。
301 → 302 → 301 → final destination最大10回までのリダイレクトを追跡バイパステクニックの検証
ドメイン検証をバイパスする一般的なテクニック(URLエンコード、ダブルスラッシュ、ドメイン偽装等)に対する耐性を検証します。
%2F%2Fevil.com///evil.comevil.com%23.example.comexample.com.evil.com攻撃シナリオ
オープンリダイレクトの悪用パターン
フィッシング攻撃の強化
危険度: 高正規サイトのドメインを含むURLをフィッシングメールに使用することで、URLフィルターやユーザーの警戒を回避できます。例えば「https://trusted-bank.com/redirect?url=https://evil-login.com」のようなURLは、ドメインが正規サイトであるため、セキュリティソフトやユーザーの目視確認をすり抜ける可能性が高くなります。
OAuth認証フローの乗っ取り
危険度: 非常に高OAuth認証のredirect_uriパラメータにオープンリダイレクトの脆弱性がある場合、認証コードやアクセストークンを攻撃者のサーバーに送信させることが可能です。これにより、被害者のアカウントへの完全なアクセスが取得されます。
SSO(シングルサインオン)の悪用
危険度: 高企業のSSO認証フローにオープンリダイレクトが存在すると、認証後のリダイレクト先を攻撃者のサイトに変更できます。ユーザーは正規のSSO画面でログインした後、気づかないうちに攻撃者のサイトにセッション情報とともに転送されます。
マルウェア配布
危険度: 中信頼されたドメインのリダイレクトを利用して、マルウェアのダウンロードページにユーザーを誘導します。ブラウザのセキュリティ警告が表示されにくくなり、ユーザーがマルウェアをダウンロードする確率が上昇します。
攻撃フロー
1. 攻撃者がフィッシングメールを送信:
"パスワードリセットはこちら: https://trusted-bank.com/redirect?url=https://evil-login.com"
2. ユーザーがリンクをクリック:
→ trusted-bank.com のドメインなので安全だと判断
3. trusted-bank.com がリダイレクトを実行:
→ HTTP 302 Location: https://evil-login.com
4. ユーザーが evil-login.com に到達:
→ 本物そっくりのログインページが表示される
5. ユーザーが認証情報を入力:
→ パスワードが攻撃者のサーバーに送信される実際の被害事例
オープンリダイレクトによる攻撃事例
Google OAuth オープンリダイレクト脆弱性
Googleの認証フローで発見されたオープンリダイレクト脆弱性。OAuth認証完了後のリダイレクト先を攻撃者のサーバーに変更することで、アクセストークンを窃取できました。Googleのドメインを経由するため、フィッシング検出システムを回避できた点が深刻でした。バグバウンティプログラムを通じて報告・修正されました。
PayPal フィッシング攻撃(オープンリダイレクト悪用)
PayPalのWebサイトに存在したオープンリダイレクト脆弱性を悪用し、paypal.comドメインを含むURLでフィッシングサイトに誘導する攻撃が報告されました。正規のPayPalドメインがURLに含まれるため、ユーザーは正規のサイトにアクセスしていると信じてログイン情報を入力してしまいました。
国内ECサイトでのリダイレクト悪用事例
日本国内の大手ECサイトで、ログイン後のリダイレクトURL(return_to パラメータ)にバリデーションが不十分な脆弱性が発見されました。攻撃者は正規のログインURLにフィッシングサイトへのリダイレクトを仕込み、ユーザーの認証情報を窃取する攻撃を実行しました。
検出メカニズム
Security Scannerの検出方法
リダイレクトパラメータの特定
URLのクエリパラメータを解析し、リダイレクトに使用される可能性のあるパラメータ(redirect, url, next, return_to等)を特定します。
外部URLの注入テスト
特定されたパラメータに外部ドメインのURLを注入し、実際にリダイレクトが発生するかを検証します。
バイパステクニックの検証
URLエンコード、ダブルスラッシュ、ドメイン偽装、NULLバイト挿入など、一般的なバイパステクニックに対する耐性を検証します。
リダイレクトチェーンの追跡
HTTP 3xx レスポンスを最大10回まで追跡し、最終的な遷移先を確認。多段リダイレクトの検出を行います。
リスクの総合評価
リダイレクトの発生有無、バイパスの可能性、Locationヘッダーの内容に基づいてリスクスコアを算出します。
修正方法
オープンリダイレクトの防御方法
1. ホワイトリスト方式(最も推奨)
リダイレクト先を事前に定義したホワイトリストで制限する方法。最も安全で確実な対策です。
// Next.js - 安全なリダイレクト実装
const ALLOWED_REDIRECT_PATHS = [
'/dashboard',
'/profile',
'/settings',
'/orders',
];
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const redirectTo = searchParams.get('redirect') || '/dashboard';
// ホワイトリストチェック
if (!ALLOWED_REDIRECT_PATHS.includes(redirectTo)) {
// 許可されていないパスはデフォルトにリダイレクト
return Response.redirect(new URL('/dashboard', request.url));
}
// 相対パスのみ許可(外部URLを排除)
if (redirectTo.startsWith('//') || redirectTo.includes('://')) {
return Response.redirect(new URL('/dashboard', request.url));
}
return Response.redirect(new URL(redirectTo, request.url));
}2. ドメイン検証(ホワイトリストが難しい場合)
リダイレクト先のドメインを厳密に検証する方法。ホワイトリスト方式が実装困難な場合の代替策です。
// ドメイン検証関数
function isAllowedRedirect(url: string, allowedDomains: string[]): boolean {
try {
const parsed = new URL(url);
// 許可されたドメインのみ
return allowedDomains.some(domain =>
parsed.hostname === domain ||
parsed.hostname.endsWith('.' + domain)
);
} catch {
// 無効なURL → 相対パスとして処理
return !url.startsWith('//') && !url.includes('://');
}
}
// 使用例
const ALLOWED_DOMAINS = ['example.com', 'app.example.com'];
function handleRedirect(redirectUrl: string): string {
if (isAllowedRedirect(redirectUrl, ALLOWED_DOMAINS)) {
return redirectUrl;
}
return '/dashboard'; // フォールバック
}3. 間接リダイレクト(IDマッピング)
URLを直接パラメータに含めず、IDでマッピングする方法。URLの直接操作を完全に排除できます。
// IDベースのリダイレクトマッピング
const REDIRECT_MAP: Record<string, string> = {
'dashboard': '/dashboard',
'profile': '/profile',
'settings': '/settings',
'billing': '/account/billing',
};
// URL: /auth/callback?next=dashboard(URLではなくIDを使用)
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const nextId = searchParams.get('next') || 'dashboard';
const redirectPath = REDIRECT_MAP[nextId] || '/dashboard';
return Response.redirect(new URL(redirectPath, request.url));
}4. 避けるべきパターン
ユーザー入力をそのままLocationヘッダーに設定
外部URLへの無制限リダイレクトが可能になる。
ブラックリスト方式(特定のドメインのみブロック)
新しいドメインや巧妙なバイパステクニックで回避される。
正規表現によるドメイン検証のみ
正規表現のバグやバイパステクニック(example.com.evil.com等)で回避される可能性がある。
JavaScriptによるリダイレクト(window.location = userInput)
javascript: プロトコルによるXSS攻撃のリスクも追加される。