【入門編】WebAuthn/FIDO2の登録・認証フローにおけるOrigin検証の重要性 – アプリケーションセキュリティ & 安全な開発防御ガイド

「鍵をかけたはずなのに泥棒に入られた?」WebAuthn/FIDO2の落とし穴と「Origin検証」の真実

こんにちは。セキュリティの世界へようこそ。
今日は、パスワードを使わない次世代の認証技術「WebAuthn/FIDO2」についてお話しします。

「生体認証やセキュリティキーを使っているから、うちはもう絶対安全だよね!」なんて思っていませんか?実は、最新の技術を使っていても、「Origin(オリジン)」という概念を軽視していると、まるで「家の鍵をかけたのに、偽物のドアに鍵をかけさせていた」ような悲劇が起きてしまうのです。

今回は、この「Origin検証」という、地味だけれど最も重要な防犯装置について、泥臭い現場の視点から紐解いていきましょう。

—

1. そもそも「Origin」って何?:家の住所を証明する仕組み

まずは、身近な例えから入りますね。
あなたが「A銀行」という立派な建物の入り口で、セキュリティキー(指紋やPIN)を使って認証を通そうとしていると想像してください。

しかし、もし誰かが「A銀行」とそっくりな外観の「偽物の建物」を隣に建てていたらどうでしょう?
あなたが偽物の建物の入り口に鍵を差し込んでも、それはA銀行のセキュリティシステムとは全くの無関係ですよね。

Webの世界における「Origin」とは、まさに「この建物は本物のA銀行ですよ」という住所そのものです。

  • Originの構成要素: プロトコル(https://) + ホスト名(example.com) + ポート番号(443)
  • これが一つでもズレていれば、ブラウザは「おっと、ここは君が登録した場所とは違うぞ!」と警告を出します。

—

2. なぜ「Origin検証」をサボると危険なのか?

WebAuthnにおいて、ブラウザは「登録した時のOrigin」と「認証しようとしているOrigin」を厳密にチェックします。これを「Originバインディング」と呼びます。

もしサーバー側でこのチェックをサボると、攻撃者は以下のような手口を使ってきます。

1. フィッシングサイトの構築: example.com(本物)を exampIe.com(小文字のLを大文字のIに変えた偽物)として構築します。
2. 認証リクエストの転送: 攻撃者は本物のサイトにアクセスし、その認証リクエストを横取りして、偽物サイトにいるあなたに投げつけます。
3. キーの紐付け: あなたが偽物サイトで指紋認証を行うと、その認証結果は「偽物サイト」と紐づいてしまい、攻撃者があなたの代わりにログインする権利を手に入れてしまうのです。

「ブラウザがチェックしてくれるから大丈夫じゃないの?」と思うかもしれませんが、サーバー側で「今届いた署名は、本当にうちのドメイン(RP ID)宛のものか?」を確認しないと、認証そのものの正当性が担保されません。

—

3. サーバー側でやるべき「RP ID」の正しい設定

サーバー側で最も重要な設定が「RP ID (Relying Party Identifier)」です。これは、あなたが運営するWebサービスのドメインを指します。

例えば、login.example.com というサービスを運営している場合、RP IDは example.com と設定するのが一般的です。

実装時のポイント(コード例)

サーバーサイドでWebAuthnの検証を行う際、以下のように「期待されるRP ID」を必ずハードコードするか、厳格な設定値として持たせてください。

// サーバー側:WebAuthn認証検証のロジック例
const expectedRpId = “example.com”; // 自分のサービスのドメインを明記!

function verifyAuthentication(clientDataJSON, rpIdFromClient) {
// 1. ブラウザから送られてきたデータからRP IDを抽出
const clientData = JSON.parse(atob(clientDataJSON));

// 2. ここが重要!受信したRP IDが、期待するものと一致するか検証する
if (clientData.origin !== “https://example.com”) {
throw new Error(“不正なOriginからのアクセスです。フィッシングの可能性があります!”);
}

if (rpIdFromClient !== expectedRpId) {
throw new Error(“RP IDが一致しません。ドメインの偽装が疑われます。”);
}

// ここで初めて署名の検証に進む
return performSignatureVerification();
}

ここでの教訓:

  • RP IDは必ずサーバー側で管理すること。
  • クライアント(ブラウザ)から送られてきた情報を「鵜呑みにしない」こと。
  • Originの比較は「部分一致」ではなく「完全一致」を基本とすること。

—

4. 今日からできる一歩先の防犯対策

「難しそうだな…」と感じた方も安心してください。まずは以下の3点をチェックリストとして持っておくだけで、セキュリティレベルはグッと上がります。

1. 環境ごとのOriginを分ける: 開発環境(dev.example.com)と本番環境(example.com)でRP IDを混同させない。
2. HTTPSの強制: HTTP(暗号化なし)ではWebAuthnは動きません。TLS証明書は必須です。
3. ライブラリの最新化: 自作の実装はバグの元です。信頼できるWebAuthnライブラリ(simplewebauthn や fido2-lib など)を利用し、常にアップデートを心がけましょう。

—

最後に:セキュリティは「疑うこと」から始まる

セキュリティの現場では、「システムは悪意ある攻撃者に囲まれている」という前提で考えるのが正解です。

今回の「Origin検証」は、家の鍵に例えるなら「ドアが本物かどうかを確認する覗き穴」のようなもの。覗き穴を塞いでしまえば、外に誰がいるのか、ドアそのものが偽物ではないか、判断できなくなってしまいますよね。

今日から皆さんのコードをレビューする際は、「このOriginチェック、本当に厳格かな?」という視点をぜひ持ってみてください。その小さな疑問が、ユーザーの大切な情報を守る最強の盾になるはずです。

また次回の記事で、より深い泥臭い現場の知見を共有しますね。安全な開発を!

コメント

タイトルとURLをコピーしました