このページは自動翻訳されています。英語の原文は こちら.

Passkeysチートシート. パスキープログラム向けの実践ガイド、展開パターン、KPI。
安全でシンプルなユーザー認証を提供することは、2024年のデジタル企業にとって必須条件です。新しいログイン標準としてのパスキーは、これらのニーズを満たす理想的なソリューションです。しかし、ユーザーにとってのパスキーの強化されたユーザーエクスペリエンスとセキュリティは、開発者として実装する際に代償を伴います。実装の難しさは、パスキーがユーザーだけでなく開発者にとっても比較的新しいこと、そしてパスワードベースの認証と比較して実装が非常に困難になる可能性があることに起因しています。実際、パスワード認証では1つのAPIエンドポイントが必要であるのに対し、パスキー認証では少なくとも4つのAPIエンドポイントが必要です。
パスキー認証を提供するためのサーバー側のコアコンポーネントの1つが**WebAuthnサーバー(緑色のライブラリ部分)**です。WebAuthnサーバーがより広範なエンタープライズスタック統合にどのように適合するかについての包括的なガイドについては、専用の記事を参照してください。
出典:Yubico
このブログ記事では、いくつかのWebAuthnサーバーライブラリ/パッケージ/SDKを比較し、違いを分析して、パスキー実装が初めての開発者向けの推奨事項を提供します。
そもそもなぜWebAuthnサーバーライブラリが必要なのかをよりよく理解するために、パスキーの実装方法を見てみましょう。原則として、ウェブサイトやアプリにパスキーを統合するには2つの方法があります。
サードパーティのパスキーソリューションは統合が容易で、通常はエンジニアリング時間(特にエッジケース、メンテナンス、リカバリ、フォールバック、および改善されたパスキーのUX)を大幅に節約できますが、一部の開発者はすべてを自分で実装することを好みます。
ライブデモでパスキーを試せます。
DIYによるパスキー実装がどのように機能するかを見てみましょう。非常に基本的なセットアップでは、登録(サインアップ)と認証(ログイン)のメカニズムが必要です。全体的なフローは似たようなスキーマに従いますが、両方のプロセス(WebAuthnセレモニーとも呼ばれます)は異なる方法で処理されます。
PublicKeyCredentialCreationOptionsおよびPublicKeyCredentialRequestOptionsと呼ばれます。これらのWebAuthnパラメーターの最も重要な部分の1つはチャレンジです。その後、WebAuthnパラメーターはフロントエンドに送り返されます。すべてのサインアップ/ログインプロセスにはこれらの手順が含まれるため、バックエンドはユーザー、パスキー、サインアップ/ログイン要求を追跡する必要があります。
Igor Gjorgjioski
Head of Digital Channels & Platform Enablement, VicRoads
We hit 80% mobile passkey activation across 5M+ users without replacing our IDP.
See how VicRoads scaled passkeys to 5M+ users — alongside their existing IDP.
Read the case studyパスキーの機能や(サードパーティのパスキーソリューションを使用しない)シンプルな実装がどのように見えるかについてより深い知識を得たい場合は、こちらのブログ記事をご覧ください。
実際のシナリオにおいて、自分でパスキーを実装する場合、サインアップとログインのための必要なAPIエンドポイントと基本的な実装を提供するだけではないことに留意してください。さらに、以下のトピックとユースケースに対処する必要があります。
ただし、基本的なパスキーの実装では、WebAuthn標準に準拠するだけで済みます。通常は、よく知られサポートされているWebAuthnサーバーライブラリを実装するだけで十分です。ライブラリはWebAuthnサーバーパラメーターを生成し、ログインチャレンジを検証するため、実質的に暗号化と最も複雑な部分を引き受けてくれます。
最新情報とサポートのためにPasskeys Communityに参加しましょう。
分析されたすべてのWebAuthnサーバーライブラリは、パスキー認証を提供するために必要な機能を提供しています。したがって、以下の基準に特に注意を払いました。
以下のWebAuthnサーバーライブラリを分析しました(2023年12月時点のGitHubスター数の降順で並べています):
実際にどれだけの人がパスキーを使っているか確認できます。
authenticatorAttachment、residentKey、requireResidentKey、およびuserVerificationなどの変数を含む必要があり、これらもW3Cのページで説明されています)type UserModel = { id: string; username: string; currentChallenge?: string; }; /** * It is strongly advised that authenticators get their own DB * table, ideally with a foreign key to a specific UserModel. * * "SQL" tags below are suggestions for column data types and * how best to store data received during registration for use * in subsequent authentications. */ type Authenticator = { // SQL: Encode to base64url then store as `TEXT`. Index this column credentialID: Uint8Array; // SQL: Store raw bytes as `BYTEA`/`BLOB`/etc... credentialPublicKey: Uint8Array; // SQL: Consider `BIGINT` since some authenticators return atomic timestamps as counters counter: number; // SQL: `VARCHAR(32)` or similar, longest possible value is currently 12 characters // Ex: 'singleDevice' | 'multiDevice' credentialDeviceType: CredentialDeviceType; // SQL: `BOOL` or whatever similar type is supported credentialBackedUp: boolean; // SQL: `VARCHAR(255)` and store string array as a CSV string // Ex: ['usb' | 'ble' | 'nfc' | 'internal'] transports?: AuthenticatorTransport[]; };
public class StoredCredential { /// <summary> /// The Credential ID of the public key credential source. /// </summary> public byte[] Id { get; set; } /// <summary> /// The credential public key of the public key credential source. /// </summary> public byte[] PublicKey { get; set; } /// <summary> /// The latest value of the signature counter in the authenticator data from any ceremony using the public key credential source. /// </summary> public uint SignCount { get; set; } /// <summary> /// The value returned from getTransports() when the public key credential source was registered. /// </summary> public AuthenticatorTransport[] Transports { get; set; } /// <summary> /// The value of the BE flag when the public key credential source was created. /// </summary> public bool IsBackupEligible { get; set; } /// <summary> /// The latest value of the BS flag in the authenticator data from any ceremony using the public key credential source. /// </summary> public bool IsBackedUp { get; set; } /// <summary> /// The value of the attestationObject attribute when the public key credential source was registered. /// Storing this enables the Relying Party to reference the credent’al's attestation statement at a later time. /// </summary> public byte[] AttestationObject { get; set; } /// <summary> /// The value of the clientDataJSON attribute when the public key credential source was registered. /// Storing this in combination with the above attestationObject item enables the Relying Party to re-verify the attestation signature at a later time. /// </summary> public byte[] AttestationClientDataJson { get; set; } public List<byte[]> DevicePublicKeys { get; set; } public byte[] UserId { get; set; } public PublicKeyCredentialDescriptor Descriptor { get; set; } public byte[] UserHandle { get; set; } public string AttestationFormat { get; set; } public DateTimeOffset RegDate { get; set; } public Guid AaGuid { get; set; } }
<?php declare(strict_types=1); namespace App\Entity; use App\Repository\PublicKeyCredentialSourceRepository; use DateTimeImmutable; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Uid\AbstractUid; use Symfony\Component\Uid\Uuid; use Webauthn\PublicKeyCredentialSource as BasePublicKeyCredentialSource; use Webauthn\TrustPath\TrustPath; #[ORM\Table(name: 'pk_credential_sources')] #[ORM\Entity(repositoryClass: PublicKeyCredentialSourceRepository::class)] class PublicKeyCredentialSource extends BasePublicKeyCredentialSource { #[ORM\Column(type: Types::DATETIME_IMMUTABLE)] public readonly DateTimeImmutable $createdAt; #[ORM\Id] #[ORM\Column(type: Types::STRING, length: 255)] #[ORM\GeneratedValue(strategy: 'NONE')] private string $id; public function __construct( string $publicKeyCredentialId, string $type, array $transports, string $attestationType, TrustPath $trustPath, AbstractUid $aaguid, string $credentialPublicKey, string $userHandle, int $counter ) { $this->id = Uuid::v4()->toRfc4122(); $this->createdAt = new DateTimeImmutable(); parent::__construct($publicKeyCredentialId, $type, $transports, $attestationType, $trustPath, $aaguid, $credentialPublicKey, $userHandle, $counter); } public function getId(): string { return $this->id; } }
discouraged、preferred、requiredの値を伴うW3C提案のUserVerificationRequirementパラメータの代わりに、webauthn4jはブール変数としてverificationRequiredとuserPrecenseRequiredを提供します以下の表は、WebAuthnサーバーライブラリの概要を示しています。
最新ニュースを受け取るためにPasskeys Substackを購読しましょう。
ほとんどのライブラリは同等に強力であり、WebAuthn標準を実装しているため、以下のディシジョンツリーをお勧めします。
go-webauthnまたはSimpleWebAuthnを使用することをお勧めします。特定のプロジェクトがまだなくてもWebAuthnサーバー全般について詳しく知りたい場合は、ライブラリとドキュメントや実装例などの補足資料との間にいくつかの違いがあるため、いくつか推奨事項があります。したがって、パスキー実装の旅をキックスタートしたいソフトウェア開発者には、以下の実装を選択することをお勧めします。
サーバー側でWebAuthnがどのように機能するかをさらに深く理解したい場合は、WebAuthn RFCの「WebAuthn Relying Party Operations」という非常に詳細なセクションを読むことができます。このセクションでは、新しいクレデンシャルの登録(7.1)および認証アサーションの検証(7.2)のために実装する必要があるすべての手順が詳しく説明されています。
具体的なパスキーとWebAuthnの要件を評価します。このブログ記事では、discoverable credentials(Discoverable Credentials)としてパスキーのみをサポートしたいと想定しています。PublicKeyCredentialCreationOptionsとPublicKeyCredentialRequestOptions、そしてクライアント側のnavigator.credentials.create()とnavigator.credentials.get()のWebAuthn API呼び出しを読んで、ユースケースに合わせてWebAuthnサーバーSDKの構成のパラメータを正しく設定してください。
すべてのWebAuthnサーバーライブラリについて、以下の情報を永続化/アクセスするための適切なデータベース構造を提供する必要があります。
一部のライブラリについては、特定の推奨事項と例があります(有用と思われる場合は上記で提供しています)。どのWebAuthnフィールドをどこに保存する必要があるかを完全に理解することが不可欠です。ユーザーID(user.id)に使用する値を特定することに特に注意を払ってください。また、ユーザーがパスキーを削除した場合にどうなるかも考慮に入れてください。それに加えて、オプションで特定のオーセンティケーターの使用を制限することができます。パスキーに関連する有効なオーセンティケーターのリストはこちらにあります。セキュリティキーの構成証明(アテステーション)もサポートして確認したい場合は、まったく別の話になります。詳細情報はこちらにあります。
ユーザーがパスキーとフォールバック認証方法を使用するデバイスを特定します。ユーザーが使用しているデバイス、ブラウザ、オペレーティングシステムがわからない場合は、プラットフォーム、ブラウザ、オペレーティングシステム全体でのパスキー対応に関する最新データについて、State of Passkeysを確認してください。特定のデバイスのパスキーの採用やパスキー対応のシェアについて具体的な質問がある場合は、お気軽にお問い合わせください。このトピックに関するさらなる洞察を提供し、サポートさせていただきます。可観測性(オブザーバビリティ)の観点からは、クライアント側のWebAuthnエラーとサーバー検証の拒否を別々のストリームとして維持します。クライアント側のバケット定義には、WebAuthnエラーを使用します。さらに、Windows 10とLinuxはパスキーのサポートが最も少ない(あるいは全くない)ため、これらのオペレーティングシステム向けに専用のソリューションを用意する必要があることに留意してください。
実際にどれだけの人がパスキーを使っているか確認できます。
現在、ほぼすべての言語やフレームワークについて、確立されたWebAuthnサーバーライブラリが存在します。異なる言語のライブラリを比較しても、特定の実装の明確な優位性は示されていません。むしろ、最も使い慣れたフレームワーク/プログラミング言語を使用する必要があります。あるいは、WebAuthnを自分で実装したくなく、付随するすべての処理を行いたくない場合は、Corbadoのような専用の構築済みパスキー認証ソリューションを試すことができます。パスキーを中心としたオールインワンの認証ソリューションとして、優れたパスキーインテリジェンス、セッション管理、およびフォールバック認証方法が備わっているため、製品の開発に集中し、認証を手放すことができます。こちらから無制限のユーザーで無料でお試しいただけます。
Corbadoは、大規模なconsumer認証を運用するCIAMチームのためのAuthentication Intelligence Platformです。IDPのログや一般的なanalyticsツールでは見えないものを可視化します。どのデバイス、OSバージョン、ブラウザ、credential managerがpasskeyに対応しているか、なぜ登録がログインにつながらないのか、WebAuthnフローのどこで失敗するか、OSやブラウザのアップデートがいつ静かにログインを壊すか — Okta、Auth0、Ping、Cognito、あるいは自社IDPを置き換えることなく、すべてを把握できます。2つのプロダクト:Corbado Observeは passkeyとその他あらゆるログイン方式のobservabilityを提供します。Corbado Connectは analytics内蔵のmanaged passkeyを追加します(既存のIDPと併用)。VicRoadsはCorbadoで500万人超のユーザーにpasskeyを提供しています(passkey有効化率+80%)。 Passkeyエキスパートに相談する →
まず、特定のフレームワーク用のライブラリが存在するかどうかを確認し、次にプログラミング言語用のライブラリを確認します。リストされているすべてのライブラリはWebAuthn標準を同等に実装しているため、ライブラリ間の機能の違いよりも、既存のスタックへの親和性を優先して選択する必要があります。
少なくとも、クレデンシャル、ユーザー、チャレンジ、およびオーセンティケーターを永続化する必要があります。ユーザーID(userHandle)としてどの値を割り当てるかに細心の注意を払い、ユーザーがデバイスからパスキーを削除するシナリオを計画してください。
WebAuthnサーバーライブラリは、PublicKeyCredentialCreationOptionsおよびPublicKeyCredentialRequestOptionsパラメータの生成や、署名されたチャレンジの検証など、最も複雑な暗号化操作を処理します。これらをゼロから正しく行うことは、すでにテストされ監査されているFIDO準拠のライブラリを使用するよりもはるかに困難です。
Windows 10とLinuxはパスキーのサポートが最も少ないため、これらのプラットフォームのユーザーには専用のフォールバックソリューションが必要です。クライアント側のWebAuthnエラーとサーバー検証の拒否を別々のストリームとして監視することで、本番環境におけるOS固有の問題を特定しやすくなります。
関連記事
目次