TL;DR

Web Authentication API の略。パスワードや SMS の代わりに公開鍵暗号を使って、Web サイトでの登録、認証、多要素認証を行うためのブラウザの API である。

なぜ必要か

  • 署名がサイトのオリジンごとに変わるので、偽サイトではログインできず、フィッシングを防げる。
  • サーバには公開鍵しか保存しないので、サーバから情報が漏れても、秘密鍵がなければ認証できない。
  • テキストのパスワードはデジタル署名よりも総当たりで破りやすい。パスワードを使わないので、使い回しによる被害も防げる。

仕組み

秘密鍵は認証器(端末の生体認証や USB のセキュリティキーなど)に残り、サーバには公開鍵だけを保存する。

登録では、サーバがユーザの情報と乱数のチャレンジをアプリケーションに渡す。アプリケーションが navigator.credentials.create() を呼ぶと、認証器がユーザの同意を得て鍵ペアを作り、公開鍵を返す。サーバはチャレンジ、オリジン、署名を検証し、公開鍵を保存する。

認証では、サーバがチャレンジと許可する資格情報の一覧を送る。アプリケーションが navigator.credentials.get() を呼ぶと、認証器が秘密鍵でチャレンジに署名する。サーバは保存しておいた公開鍵で署名を検証する。

// 登録
const credential = await navigator.credentials.create({
  publicKey: {
    challenge: new Uint8Array([/* サーバから受け取った乱数 */]),
    rp: { id: "acme.com", name: "ACME Corporation" },
    user: {
      id: new Uint8Array([/* ユーザ固有の ID */]),
      name: "jamiedoe",
      displayName: "Jamie Doe",
    },
    pubKeyCredParams: [{ type: "public-key", alg: -7 }],
  },
})

例

パスキーは、WebAuthn の検出可能な資格情報(discoverable credentials)を使った代表的な例である。

注意点

HTTPS などの安全なコンテキストでしか動かない。チャレンジは 16 バイト以上のランダムな値にする。

関連

出典