パスキーは、ブラウザでWebAuthn APIを呼び出すだけで完成する認証機能ではありません。
利用者の端末では、OSや認証器が秘密鍵を生成・保護し、顔認証、指紋認証、PINなどによるユーザー検証を行います。一方、Webサービス側では、チャレンジの発行、登録情報の保存、署名検証、セッション発行、パスキーの追加・削除、端末紛失時の復旧などを設計する必要があります。
このページでは、パスキーを自社のWebサービスへ実装する開発者を対象として、Webサービス、ブラウザ、OS、認証器がそれぞれ何を担当するのかを整理します。
また、自営実装、既存IdP、パスキー認証APIという3つの導入方法を比較し、自社に適した構成を判断するための基礎知識を解説します。
パスキー認証の仕組みを理解するには、最初に登場する主体を分けて考える必要があります。
一般向けの説明では、利用者、Webサービス、認証器の3者に整理されることがあります。しかし、開発者向けには、Webサービスと認証器を仲介するClientを含めた4者で考える方が、処理の責任分界を正確に理解できます。
| 構成要素 | 日本語 | 主な役割 |
|---|---|---|
| User | 利用者 | 登録・認証操作を開始し、端末上で本人確認を行う |
| RP(Relying Party) | Webサービス | 登録情報を保存し、認証結果を検証してログイン可否を判断する |
| Client | ブラウザ・OS | RPとAuthenticatorを仲介し、WebAuthn処理、オリジン確認、認証UIの表示を担う |
| Authenticator | 認証器 | 鍵ペアを生成・保護し、ユーザー検証後に秘密鍵を使って署名する |
RPは、利用者へWebサービスを提供する主体です。パスキーの登録時には公開鍵などのCredential情報を保存し、ログイン時にはAuthenticatorが生成した署名を検証します。
開発者が自社のログイン基盤へパスキーを実装する場合、自社システムがRPになります。したがって、チャレンジの生成、登録情報の保存、署名検証、ユーザーとの紐付け、認証後のセッション発行は、原則としてRP側の責任です。
ブラウザやOSは、RPから渡されたWebAuthnオプションをAuthenticatorへ伝え、Authenticatorから返された結果をRPへ返します。
このときClientは、現在表示しているWebサイトのOriginやRP IDに関係する情報を認証処理へ組み込みます。これにより、正規サイト用のCredentialが異なるドメインの偽サイトで使用されにくい構造が作られます。
Authenticatorは、公開鍵と秘密鍵のペアを生成し、秘密鍵を保護します。ログイン時には、端末上で顔認証、指紋認証、PINなどのユーザー検証を行い、許可された場合に限り秘密鍵を使用して署名します。
Authenticatorには、スマートフォンやパソコンに内蔵されたPlatform Authenticatorと、USB・NFC・Bluetoothなどで接続するセキュリティキーのようなRoaming Authenticatorがあります。
FIDO2、WebAuthn、CTAPは同じ意味ではありません。それぞれが異なる範囲を担当しています。
| 用語 | 担当する範囲 | Web開発者との関係 |
|---|---|---|
| FIDO2 | 公開鍵認証をWebや端末で利用するための全体的な枠組み | WebAuthnとCTAPを組み合わせた認証基盤として理解する |
| WebAuthn | Webサイト、ブラウザ、認証器をつなぐWeb標準API | フロントエンドとバックエンドの双方で実装対象になる |
| CTAP | Clientと外部Authenticatorの通信仕様 | 通常のWebサービス開発者がCTAP自体を実装することは少ない |
フロントエンドでは、ブラウザが提供するCredential Management APIを通じてWebAuthnを利用します。
パスキー登録では、主に次の関数を呼び出します。
navigator.credentials.create({
publicKey: creationOptions
});
登録済みパスキーによる認証では、主に次の関数を呼び出します。
navigator.credentials.get({
publicKey: requestOptions
});
ただし、これらの関数に値を渡すだけでは認証基盤は完成しません。creationOptionsやrequestOptionsはバックエンドで生成し、ブラウザから返された結果はバックエンドで検証する必要があります。
USBセキュリティキーや別のスマートフォンを認証器として使用するとき、ClientとAuthenticatorの間ではCTAPが利用されます。
Webサービス開発者は、通常CTAPの通信コードを直接作成しません。ブラウザやOSが、接続されたAuthenticatorとの通信を処理します。
スマートフォンやパソコンに認証器が内蔵されている場合、ブラウザ、OS、Authenticatorが一体化して見えます。しかし、論理的には、WebAuthn APIを受け付けるClientと、秘密鍵を扱うAuthenticatorは異なる役割を持ちます。
Webサービスは公開鍵を保存しますが、秘密鍵を保存しません。秘密鍵の生成、保護、利用許可は、利用者側のAuthenticatorと、その周辺にあるOSやパスキープロバイダーが担います。
代表的な環境には、次のようなものがあります。
秘密鍵を安全に保護するには、端末の画面ロック、セキュア領域、TPM、Secure Enclave、生体認証センサーなどと連携する必要があります。
これらはWebサイトから直接制御できる機能ではありません。そのため、OSや端末のセキュリティ基盤が、Authenticatorの利用、本人確認画面、鍵の保存、同期、復旧などを担当します。
Webサービス開発者は、通常「顔認証を使用する」「指紋認証だけを使用する」「PINを禁止する」といった指定をWebAuthnで直接行いません。
開発者が指定するのは、ユーザー検証を必須にするか、推奨にするか、要求しないかといった認証ポリシーです。
authenticatorSelection: {
userVerification: "required"
}
userVerification: "required"は、Authenticatorに対してユーザー検証を必須とする指定です。しかし、実際に顔、指紋、端末PINのどれを表示するかは、OS、端末、Authenticator、利用可能なハードウェア、利用者の設定によって決まります。
| 用語 | 意味 | 例 |
|---|---|---|
| User Presence(UP) | 利用者がその場で認証操作を行ったことを確認する | セキュリティキーのボタンを押す |
| User Verification(UV) | 操作している人物が正当な利用者であることを端末側で確認する | 顔認証、指紋認証、端末PIN |
重要なWebサービスでは、認証結果に含まれるUVフラグを確認し、要求したユーザー検証が実施されたことをサーバ側で検証する必要があります。
パスキーは、保存方法によって大きく同期パスキーとデバイス固定パスキーに分けられます。
「非同期パスキー」という表現でも意味は伝わりますが、特定端末やセキュリティキーにCredentialが固定される性質を表すには、Device-bound Passkey、すなわちデバイス固定パスキーという表現が適しています。
| 種類 | 保存と利用 | 主な特徴 |
|---|---|---|
| 同期パスキー | パスキープロバイダーを通じて複数端末で利用できる | 機種変更や複数端末で利用しやすい |
| デバイス固定パスキー | 特定の端末やセキュリティキーに固定される | 鍵を保持する物理デバイスを明確に限定しやすい |
同期パスキーでは、顔画像や指紋情報が同期されるわけではありません。同期対象は、パスキーとして利用する鍵情報と関連データです。
パスキープロバイダーは、利用者のアカウント、端末ロック、復旧処理などを組み合わせて鍵情報を保護し、同じ利用者が管理する別端末でも利用できるようにします。
Webサービス開発者が、秘密鍵をGoogle、Apple、Microsoftなどのクラウドへ送信するコードを書くわけではありません。
RPから見ると、同期パスキーもデバイス固定パスキーも、登録済みの公開鍵Credentialとして扱います。同期するかどうかは、Authenticatorやパスキープロバイダー側の責任範囲です。
WebAuthnのAuthenticator Dataには、AuthenticatorやCredentialの性質を判断するためのフラグが含まれる場合があります。
これらは、同期可能性や現在の状態を把握する補助情報になります。ただし、特定ベンダーの同期先や具体的な保存場所を完全に特定する情報ではありません。
一般消費者向けサービスでは、利便性の高い同期パスキーが適しています。一方、管理者権限、社内システム、金融取引などでは、会社支給端末や特定のセキュリティキーに限定したい場合があります。
その場合は、Attestation、端末管理、認証器ポリシー、IdPの条件付きアクセスなどを組み合わせて設計します。
パソコンでWebサービスへログインしようとした際、そのパソコンに対象のパスキーが保存されていなくても、スマートフォンに保存されたパスキーを利用できる場合があります。
一般的には、パソコンのブラウザにQRコードを表示し、スマートフォンで読み取ります。スマートフォン上で顔認証、指紋認証、PINなどを行うと、パソコン側のログインが完了します。
クロスデバイス認証では、スマートフォン内の秘密鍵をパソコンへコピーしません。
スマートフォン側のAuthenticatorが秘密鍵を使って署名を作成し、その認証結果が安全な通信経路を通じてパソコン側のWebAuthn処理へ返されます。
QRコードを読み取っただけで、世界中の別端末から無制限に認証できる構造ではありません。実装環境では、Bluetoothなどを利用した近接性の確認や、一時的な暗号化通信路の確立が組み合わされます。
| 方式 | 仕組み | 秘密鍵の扱い |
|---|---|---|
| 同期パスキー | 同じパスキープロバイダーの複数端末でCredentialを利用可能にする | 保護された鍵情報がプロバイダーの仕組みで同期される |
| クロスデバイス認証 | 別端末にあるパスキーを、その場の認証器として利用する | 秘密鍵は認証を行うスマートフォン側から出ない |
通常のWebサービス開発者が、QRコード通信、Bluetooth近接確認、端末間暗号化を独自実装するわけではありません。
RPがWebAuthnの標準仕様に沿って認証を開始すると、対応するブラウザとOSがクロスデバイス認証の候補を表示し、必要な処理を実行します。
パスキーによるログインは、登録済みの秘密鍵を利用できる人物であることを高い確度で確認します。
しかし、最初にそのパスキーを登録した人物が、本当に対象アカウントの正当な利用者だったかどうかは、Webサービス側の登録プロセスで担保しなければなりません。
不正な第三者にパスキー登録を許可すると、その後は不正な第三者がパスキーを使って安全かつ簡単にログインできてしまいます。
登録は、次のような強い本人確認を完了した状態でのみ許可することが重要です。
ログイン済みセッションであっても、長時間経過したセッションや、本人確認強度の低いセッションから無条件でパスキーを追加できる設計は避けるべきです。
パスキーの追加、削除、アカウント復旧先の変更などは、再認証やStep-up Authenticationを要求する重要操作として設計します。
同期パスキーは、Apple、Google、Microsoftなどのアカウント保護、端末ロック、復旧機能の上に構築されています。
しかし、これらのプラットフォームが強固であっても、RP側の登録導線が弱ければ不正登録の危険は残ります。
次の2つは分けて設計する必要があります。
パスキーをすべて失った利用者のために復旧手段は必要です。しかし、復旧方法がメールだけ、簡単な秘密の質問だけなど、パスキーより弱い認証で構成されていると、攻撃者は復旧経路を狙います。
登録、追加、削除、紛失、復旧を一つのライフサイクルとして設計することが必要です。
パスキーには、Credentialを新しく作成してRPへ公開鍵を保存する登録と、登録済みの秘密鍵で署名して本人確認を行う認証があります。
登録ではnavigator.credentials.create()を使用し、認証ではnavigator.credentials.get()を使用します。
const credential = await navigator.credentials.create({
publicKey: creationOptions
});
バックエンドから受け取ったBase64URL形式のChallengeやUser IDは、WebAuthn APIが要求するArrayBufferへ変換する必要があります。
また、Authenticatorから返されたArrayBufferを、サーバへ送信できるBase64URLなどの形式へ変換します。
const assertion = await navigator.credentials.get({
publicKey: requestOptions
});
パスキー認証では、署名が数学的に正しいことだけでなく、その署名が自社の正しい認証要求に対して作られたことを確認する必要があります。
| 検証対象 | 確認する理由 |
|---|---|
| Challenge | RPが今回発行した一度限りの認証要求に対する応答か確認する |
| Origin | 想定したWebサイトから開始された処理か確認する |
| RP ID Hash | 対象RPに結び付いたCredentialであることを確認する |
| type | 登録・認証の想定した処理種別か確認する |
| Credential ID | 対象ユーザーへ登録済みのCredentialか確認する |
| 署名 | 登録済み公開鍵に対応する秘密鍵で作成されたことを確認する |
| UP・UVフラグ | 利用者操作と要求したユーザー検証が実施されたか確認する |
| sign count | 複製された認証器の兆候を確認する補助情報として利用する |
Discoverable Credentialを利用すると、RPがあらかじめCredential IDを指定しなくても、Authenticatorが対象RPに対応するパスキーを提示できます。
これにより、ユーザー名を入力せずにパスキー候補からアカウントを選択するログインや、Conditional UIを利用した入力フォーム統合が可能になります。
WebAuthn APIはブラウザから利用できますが、パスキー認証の安全性を成立させる中心は、RPバックエンドで行う検証と、登録情報を管理するDBにあります。
自営実装では、フロントエンド、バックエンド、DB、セッション管理、アカウント復旧、監査、互換性試験までを横断して設計する必要があります。
navigator.credentials.create()による登録処理navigator.credentials.get()による認証処理| 項目 | 用途 |
|---|---|
| Credential ID | 登録された公開鍵Credentialを一意に識別する |
| User ID・User Handle | CredentialとRP側ユーザーを紐付ける |
| Public Key | 認証時の署名検証に使用する |
| Public Key Algorithm | 署名検証に利用するアルゴリズムを識別する |
| Sign Count | Authenticatorの複製兆候を確認する補助情報 |
| Transports | 利用可能な認証器の接続方法を記録する |
| AAGUID | Authenticatorの機種・種別に関する識別情報 |
| Backup Eligibility・Backup State | 同期やバックアップに関する状態を管理する |
| 登録名・端末名 | 利用者が複数パスキーを管理しやすくする |
| 登録日時・最終利用日時 | 管理画面表示、監査、不審利用の確認に使用する |
| 有効・無効・削除状態 | 紛失端末や退職者のCredentialを停止する |
WebAuthnのバイナリ解析、CBOR、COSE公開鍵、Attestation、署名検証をすべて独自実装することは推奨されません。通常は、利用する言語・フレームワークに対応した実績のあるWebAuthnライブラリを使用します。
ただし、ライブラリを導入しても、次の設計は自社に残ります。
パスキーは、JavaScriptを数行追加するだけで完成する機能ではありません。
自営実装では、次の領域を横断できる知識が必要です。
実装自体は可能ですが、正しく運用するには、フルスタック開発と認証セキュリティの両方を理解する体制が必要です。
パスキーを導入する方法は、完全な自営実装だけではありません。現在の認証基盤、ユーザーDB、開発体制、必要なカスタマイズ性に応じて、次の3方式から選択できます。
自社サービスがRPとなり、登録、認証、署名検証、Credential DB、管理画面、復旧、監査をすべて自社で構築します。
認証基盤を自社の中核機能としたい場合や、特殊な認証ポリシー、独自の端末制御、特殊な業務要件がある場合に適しています。
Microsoft Entra ID、Auth0、Okta、Amazon Cognito、Firebase AuthenticationなどのIdPを利用している場合、管理画面やSDKの設定によりパスキーを有効化できることがあります。
すでにユーザー管理とログイン画面をIdPへ委ねている場合は、比較的導入しやすい方法です。
一方、既存の自社ユーザーDB、独自ログイン画面、認証後の業務フローを維持したい場合は、IdPの設計へ合わせるための改修が必要になることがあります。
既存のユーザーDBやWebサービスを維持しながら、パスキーの登録、Challenge管理、署名検証、Credential管理などの専門領域を外部の認証サービスへ委ねる方法です。
Webサービス側は、ユーザーをパスキー登録・認証画面へ誘導し、APIやWebhookなどで認証結果を受け取ります。
| 比較項目 | 完全自営 | 既存IdP | 認証API |
|---|---|---|---|
| 既存ユーザーDB | 維持できる | IdP構成に依存する | 維持しやすい |
| WebAuthn署名検証 | 自社で実装 | IdPが担当 | 認証サービスが担当 |
| Challenge管理 | 自社で実装 | IdPが担当 | 認証サービスが担当 |
| Credential DB | 自社で管理 | IdPが管理 | 認証サービスが管理 |
| ログイン画面 | 自由に設計可能 | IdPの仕様に依存 | 既存画面と連携しやすい |
| 初期開発負荷 | 大きい | 既存利用中なら小さい | 小さくしやすい |
| 継続保守 | 自社 | IdP中心 | 認証サービス中心 |
| カスタマイズ性 | 高い | IdPの範囲内 | API仕様の範囲内 |
Push! Passkeyは、既存のWebサービスへパスキーを追加するための認証APIです。
自営実装で必要になる次の領域を、認証基盤側へ切り出します。
認証APIを利用しても、サービス側の本人確認とログイン後の権限管理まで外部サービスが自動的に決めるわけではありません。
既存サービス側では、主に次を担当します。
完全自営では、自社がWebAuthn認証基盤そのものを構築します。
Push! Passkeyを利用する場合、自社は認証基盤を一から作るのではなく、既存サービスのログインフローへパスキー認証結果を組み込むことに集中できます。
既存のユーザーDBや業務システムを維持しながら、WebAuthnの複雑な検証処理、Credential管理、OS・ブラウザ対応を認証サービスへ委ねたい場合に適した方式です。
パスキーでは、秘密鍵の生成や生体認証をOSとAuthenticatorが担います。そのため、Webサービス開発者が暗号デバイスや顔認証機能を一から作る必要はありません。
一方、RPには、登録前の本人確認、Challenge管理、Origin・RP IDの検証、公開鍵保存、署名検証、複数パスキー管理、紛失・復旧、監査ログなどの責任があります。
したがって、自営実装の判断では、単に「ブラウザがWebAuthnへ対応しているか」だけでなく、次の点を確認する必要があります。
認証基盤そのものが自社サービスの中核であれば、自営実装には大きな価値があります。
一方、既存サービスへ短期間でパスキーを追加し、認証以外の本来の機能開発に集中したい場合は、IdPやPush! Passkeyのような認証APIを利用する方法が合理的です。