認証の「終わりの始まり」:パスワードレス時代にXSSをどう制するか
やあ、エンジニア諸君。今日も脆弱性との終わりのない追いかけっこ、ご苦労様。
「パスワードレス認証(WebAuthn/FIDO2)を導入したから、うちはもう安泰だ」なんて考えていないか? もしそうなら、君はサイバー攻撃者の「最も狩りやすいカモ」だ。今日は、次世代の認証基盤を導入してもなお、XSS(クロスサイトスクリプティング)という「古典的かつ凶悪な亡霊」が、いかにして認証を無効化しうるか、そしてそれをどう封じ込めるかを徹底的に叩き込む。
—
1. なぜFIDO2でもXSSは「致命傷」なのか
FIDO2は公開鍵暗号方式を用いている。サーバーには公開鍵だけを置き、秘密鍵はユーザーのデバイス(TPM/Secure Element)から一歩も外に出ない。パスワードをネットワークに流さないため、フィッシング耐性は極めて高い。
しかし、攻撃者は「パスワード」を盗もうとはしない。 彼らが狙うのは、認証が完了した後の「セッション」だ。
攻撃シナリオ:XSSによるセッションハイジャック
XSSで を注入し、document.cookie からセッションIDを盗むのは教科書通りだ。もしアプリケーションが HttpOnly 属性を忘れていれば、君がどれほど強力なFIDO2認証を導入しようが、攻撃者は「認証済みユーザー」としてシステムに侵入できる。
さらに恐ろしいのは、DOM型XSSを利用した「認証プロセスの操作」だ。認証完了後のコールバック処理を書き換え、認証要求そのものを改ざんする攻撃が、現役の攻撃手法として存在している。
---
2. 現場で使える「XSS防御」の鉄則
XSSを防ぐには「入力値の検証」よりも「出力時のエンコード」と「ブラウザのセキュリティ機能の強制」が重要だ。
実装コード:セキュアなPHP/JSのポイント
まずは、基本中の基本である「Cookieの保護」と「出力エスケープ」を徹底する。
【PHP: セッションIDを保護する設定】
php.ini またはアプリケーション起動時に必ず適用せよ。
0,
'path' => '/',
'domain' => 'example.com',
'secure' => true, // HTTPS必須
'httponly' => true, // JSからのCookieアクセスを禁止(XSS対策の要)
'samesite' => 'Strict' // CSRF対策
]);
session_start();
【JavaScript: セキュアな出力処理(DOM型XSS対策)】
innerHTML を使ってはいけない。これはエンジニアにとっての「毒」だ。
// 危険なコード:ユーザー入力をそのままHTMLとして埋め込む
// element.innerHTML = userInput;
// 安全なコード:textContent を使用する
const div = document.getElementById('user-profile');
div.textContent = userInput; // これにより自動的にHTMLエスケープが適用される
---
3. WebAuthn実装時の「落とし穴」を塞ぐ設定
WebAuthnを実装する際、origin の検証が甘いと、攻撃者に認証要求を横取りされる可能性がある。サーバーサイドでは、必ず Relying Party ID (RP ID) を厳密にチェックすること。
NginxでのCSP(Content Security Policy)設定
XSSを防ぐ最後の砦はCSPだ。ブラウザに対し「どのスクリプトなら実行していいか」を厳格に指示する。
【nginx.conf の設定例】
信頼できないインラインスクリプトを一切禁止する(nonceを使用するのがベスト)
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'none';";
script-src 'self':自ドメイン以外のスクリプト実行を遮断。frame-ancestors 'none':クリックジャッキングを防止。
---
4. プロの視点:泥臭いインシデントハンドリングの教訓
私が過去に対応した某社の大規模漏洩事件では、WebAuthnを導入していたにもかかわらず、「認証後のリダイレクト先をURLパラメータで動的に制御していた」ことが原因で、DOM型XSSをトリガーとしたセッションの乗っ取りが発生した。
教訓:
1. リダイレクト先はホワイトリストで管理せよ: パラメータでURLを渡すのは論外だ。
2. 認証と認可の分離: 認証(あなたは誰か)が完了しても、その後の認可(何ができるか)のスコープを極限まで絞れ。
3. 「信頼」をコードに書くな: 全てのユーザー入力を「悪意あるコード」と見なすゼロトラストな実装が、君のキャリアを守る。
まとめ
FIDO2は素晴らしい技術だが、それはあくまで「鍵」の話だ。その鍵で開けた扉の向こう側に「誰もが自由に書き込める壁」があれば、泥棒は侵入する。
君たちが今日書くコードの1行1行が、明日発生するかもしれないインシデントの芽を摘んでいるんだ。その誇りを胸に、まずは手元の innerHTML を textContent に書き換えることから始めよう。
質問があればいつでも来い。現場の最前線で待っている。
コメント