WWDC Quick Look 💓 By SwiftGGTeam
Verify identity documents on the web

Verify identity documents on the web

元の動画を見る

ハイライト

本セッションでは 2 つの API 実装を一通りカバーします。Web 側の W3C Digital Credentials API と、iOS 側の IdentityDocumentServices framework です。


主要内容

オンライン本人確認の現状はかなり厳しいものです。ユーザーはまず実物の証明書を取り出し、きれいな背景を探し、ぼやけていない写真を撮影して Web サイトにアップロードする必要があります。一方の Web サイト側も、その写真が本物かどうかを判定するために大規模な画像認識システムを構築しなければなりません。このフローは双方にとって不便で、しかも偽造されやすいという問題があります。

WWDC25 では、この課題に対する完全な代替手段が示されました。Safari と WebKit が W3C Digital Credentials API に対応し、navigator.credentials.get() から ISO 18013-5 標準に準拠した mobile document(mdoc)を直接リクエストできるようになっています。ユーザーはシステム UI 上で発行元を選択します。Apple Wallet 内の運転免許証、あるいはサードパーティの Document Provider app(デモでは Local Driving Authority)などです。Face ID で認可すると、暗号化されたレスポンスがそのまま Web サイトのサーバーに返ってきます。経路は end-to-end で暗号化されており、ブラウザや OS でさえ証明書の中身を読むことはできません。あわせて、iOS 側には新フレームワーク IdentityDocumentServices が用意され、身分証明書を扱う任意の app が UI App Extension としてシステムの選択画面に登場できるようになります。


詳細

Web サイト側のリクエストは 2 つに分かれます。Device Request と Encryption Information です(10:17)。Device Request では docType 文字列で運転免許証をリクエストすることを宣言し、必要なフィールド(given name、family name、age over 21、portrait、driving privileges)を列挙します。Encryption Information ではリプレイ攻撃を防ぐための nonce を生成し、さらに recipient encryption key-pair を生成します。公開鍵をリクエストに含めて provider に送り、秘密鍵はサーバー側に保持しておき、レスポンスが返ってきた際の復号に使います。

署名は Apple Business Connect 経由で行います。まず署名用の鍵ペアを生成し、CSR を提出して証明書を取得します。実行時にはサイトの origin URL と Encryption Information を組み合わせて Session Transcript を計算し、証明書で署名して Signed Authentication Structure を作成、これを Reader Authentication All リストに格納します(13:16)。このリストは配列なので、1 つのリクエストを複数の provider が信頼する証明書で同時に署名することも可能です。たとえば Apple Wallet と Local Driving Authority の両方を同時にサポートする、といったケースです。

フロントエンドの呼び出しはシンプルです。

const response = await navigator.credentials.get({
  digital: {
    requests: [{
      protocol: "org-iso-mdoc",
      data: requestData
    }]
  }
});

ポイントは次のとおりです。

  • protocol フィールドには標準化された文字列 org-iso-mdoc を必ず指定します。ブラウザはこれを見て mdoc リクエストであると識別します。
  • data はサーバー側で構築・署名済みのリクエストバイナリです。フロントエンドは構築には関与しません。
  • navigator.credentials.get() はユーザージェスチャー(クリックやキー入力)の中で呼び出す必要があります。そうでないとブラウザに拒否されます。
  • 返ってくる response は JSON-serializable なので、そのまま fetch や XHR でサーバーに送って復号できます。
  • API は豊富な例外型を提供しており、catch 句で従来の「証明書の写真をアップロードする」フローへフォールバックできます(15:08)。

レスポンスの復号は HPKE(RFC-9180)を使います(18:05)。入力は暗号文、provider の sender public key、サーバー側で先に生成した recipient private key、そして署名時と同一の Session Transcript です。復号すると Device Response が得られます。各ドキュメントには Mobile Security Object が含まれており、これは immutable で issuer によって署名されており、すべてのフィールドの hash digest が格納されています。検証フローは次のようになります。まず Document Signer Certificate が信頼できる Issuing Authority root までチェーンできるかを検証します。次に返却された各フィールドの digest を計算し、MSO 内の digest と突き合わせます。最後に MSO 内の Device Public Key を使って Device Authentication を検証し、この mdoc が確かに発行元のデバイスから来たものであり、複製されていないことを確認します(20:32)。

iOS 側の Document Provider の登録フローはこのようになります(26:19)。

let store = IdentityDocumentProviderRegistrationStore.shared

let registration = MobileDocumentRegistration(
    mobileDocumentType: .mDL,
    authorityKeyIdentifiers: trustedAuthorities,
    documentIdentifier: localStorageID
)

try await store.addRegistration(registration)

ポイントは次のとおりです。

  • IdentityDocumentProviderRegistrationStore がすべての登録操作のエントリポイントです。
  • mobileDocumentType には標準化された文字列を指定します。mDL は mobile driver’s license に対応します。
  • authorityKeyIdentifiers によって、どの証明書で署名されたリクエストがこの app をトリガーするかが決まります。リストにない要求元のリクエストでは、app はシステム選択画面に表示されません。
  • documentIdentifier は app 側のローカル ID で、システム上の登録と app 内部に保存している mdoc を対応付けるために使います。
  • ユーザーが app 内で証明書を削除する際は、同じ ID を渡して removeRegistration() を呼び出すだけでオフラインにできます。
  • registrations プロパティを参照すれば、現在登録されているすべての項目を列挙して照合することも可能です。

UI 部分は Xcode の Identity Document Provider テンプレートから App Extension として生成します(28:19)。設計上もっとも重要なのが partial request です。システムはまずサンドボックス内でリクエストの一部だけをパースし、署名検証を行ったうえで、UI 構築に必要な情報(document requests、authentication certificates)のみを app に渡します。完全な ISO 18013 Device Request は、ユーザーが app 内で「承認」を押した時点で初めて、sendResponse() クロージャの rawRequest パラメータ経由で app に渡されます。app は完全なリクエストを受け取った後、まず partial request との一貫性チェックを行い、署名を検証し、レスポンスを構築・暗号化します。この設計によって「認可前に OS コンポーネントが任意のネットワークデータをパースする」という攻撃面が、サンドボックス内に閉じ込められています。


重要ポイント

  • 何をするか: 「証明書の写真をアップロード」フローを Digital Credentials API 入口へアップグレード

    • なぜ取り組む価値があるか: 実物の証明書を撮影するフローはコンバージョン率に天井があります。写真の品質、光の状態、人手によるレビューがすべて経路を遅くします。Digital Credentials なら最初から暗号化された署名検証可能な構造化データが得られ、OCR や不正検知システムの作業の大半を省けます。
    • どう始めるか: development-signed build でフロー全体を検証します(開発環境では Oblivious HTTP Relay の審査が不要)。その後 Apple Business Connect で署名証明書を申請し、ISO 18013-7 Annex C に従ってサーバー側の構築・復号ロジックを実装します。
  • 何をするか: 従来のアップロード方式をフォールバックとして残す

    • なぜ取り組む価値があるか: 古いブラウザ、証明書を未登録のユーザー、海外ユーザーなどは Digital Credentials API をサポートしていない可能性があります。一気に切り替えると一部の注文が直接落ちてしまいます。
    • どう始めるか: navigator.credentials.get() を try-catch で囲み、標準的な例外をキャッチします。例外の種類に応じてリトライするか、ユーザーに通知するか、HTML form のアップロードへフォールバックするかを決めます。catch して何もしないのは避けてください。
  • 何をするか: 身分証明書系の app を IdentityDocumentServices に対応させる

    • なぜ取り組む価値があるか: 政府、業界団体、企業が発行する電子証明書を、同じシステム選択画面を通じて Safari やほかの app のリクエストから扱えるようになります。独自の deep link を実装したり、個別に統合交渉をしたりする手間が省けます。
    • どう始めるか: Xcode の Identity Document Provider テンプレートから新規 App Extension を作成します。performRegistrationUpdates() でローカルの mdoc を IdentityDocumentProviderRegistrationStore に同期し、RequestAuthorizationView で認可 UI を実装します。
  • 何をするか: 最小開示原則でリクエストフィールドを絞る

    • なぜ取り組む価値があるか: ユーザーは認可画面で完全なリクエスト一覧を確認します。要求するフィールドが多すぎると認可率が下がりますし、コンプライアンスの調査対象にもなりかねません。
    • どう始めるか: 既存の検証フローを棚卸しし、「氏名 + 21 歳以上かどうか」のように業務上本当に必要なフィールドだけを抽出します。Device Request の namespace で宣言する element identifier はそれだけに絞り、ついでに証明書全体を取りに行くことは避けてください。

関連セッション

コメント

GitHub Issues · utterances