メール検証 API

コミュニティグループ報告書草案,

このバージョン:
https://github.com/WICG/email-verification
課題追跡:
GitHub
著者:
Sam Goto, Google, goto@google.com
Dick Hardt, Hellō, dick.hardt@gmail.com

概要

この文書はメール検証プロトコル(EVP)を定義します。このプロトコルにより、Web アプリケーションは検証メールを送信することなく、ユーザーが メールアドレスを管理していることを検証できます。このプロトコルは、ブラウザーが検証者と発行者の間を仲介する三者モデルを使用し、 ユーザー体験の向上とプライバシー保護の両方を実現します。

この文書の位置付け

この仕様は、Web Platform Incubator Community Group によって公開されました。 これは W3C 標準ではなく、W3C 標準化過程にもありません。 以下の W3C Community Contributor License Agreement (CLA) では、限定的なオプトアウトが認められており、その他の条件も適用されることに注意してください。 W3C Community and Business Groups の詳細をご覧ください。

1. はじめに

従来、アカウント作成、サインイン、またはアカウント復旧時のメールアドレスの検証は、 手動による帯域外の仕組みに依存してきました。一般的なフローでは、Web サイトがワンタイムパスコード(OTP)または 「マジックリンク」をユーザーのメールアドレスに送信します。その後、ユーザーはメールの受信トレイに移動し、 コードを取得するかリンクをクリックしてから、Web サイトに戻って所有権を証明する必要があります。

このプロセスは大きな摩擦をもたらし、ユーザー体験とコンバージョン率に影響を与えます。さらに、 悪意のあるサイトがユーザーを欺いて OTP を提供させるフィッシング攻撃に対して脆弱です。

メール検証プロトコル(EVP)は、メールの所有権を暗号学的に検証するための、ブラウザーを介した仕組みを導入します。 ユーザーとメールプロバイダー(発行者)の間のアクティブなセッションを活用することで、 ブラウザーは暗号学的に署名されたメール検証トークン(EVT)を要求し、それを Web サイト(検証者)に提示できます。

この仕様は、検証者が EVT を要求するために使用する HTML の拡張と、トークンを取得するために発行者と連携する クライアント側のブラウザーの動作を定義します。

1.1. プロトコルの概要

このプロトコルには、3 つの主要な当事者が関与します:

一般的なフローは、次の手順で構成されます:

  1. ログイン: ユーザーがメールプロバイダーにログインします。プロバイダーはブラウザーの ログイン状態を ログイン済み に更新します( ログイン状態 API を使用します)。

  2. 要求: 検証者の Web サイトには、 autocomplete="email-verification-token"nonce 属性を持つ非表示の入力フィールドが含まれます。

  3. 発見と検証: ユーザーがメールアドレスを選択すると(たとえば、 自動入力を介して)、UA は DNS を介して権威のある発行者を発見します。UA は、ユーザーがその発行者との アクティブなセッションを持っているかどうかを確認します。

  4. 発行: UA は発行者に EVT を要求します。

  5. バインドと提示: UA は検証者のオリジンと nonce を EVT にバインドし、 鍵バインド JWT(KB-JWT)を作成して、フォームの 送信前に検証者の入力フィールドへ入力します。

  6. 検証: 検証者は EVT と KB-JWT を検証して、検証を完了します。

1.2.

この節は非規範的です。

登録時にユーザーのメールアドレスを検証しようとする検証者の Web サイト https://rp.example を考えます。

1.2.1. 検証者の HTML フォーム

検証者は、標準のメール入力と、メール検証トークン(EVT)用の非表示入力を、 autocomplete="email-verification-token" および一意の nonce とともに含めます:

<form action="/signup" method="post">
  <label for="email">メールアドレス:</label>
  <input type="email" id="email" name="email" autocomplete="email">

  <!-- EVP の非表示入力 -->
  <input type="hidden" name="evt" 
         autocomplete="email-verification-token" 
         nonce="xyz123456789">

  <button type="submit">登録</button>
</form>

1.2.2. ブラウザーとの対話

  1. ユーザーが email 入力にフォーカスすると、ブラウザーは自動入力用のメールアドレスを 提案します(たとえば、user@email.example)。

  2. ユーザーは user@email.example を選択します。

  3. ブラウザーは発行者の発見(email.exampleissuer.example に委任されていることの検出)を実行し、発行者とのユーザーのセッションを検証して、次のプロンプトを表示します: メールを検証しますか? user@email.example の検証済みトークンを rp.example と共有しますか? [許可] [拒否]

  4. ユーザーが「許可」を選択すると、ブラウザーは issuer.example から EVT を取得し、それを rp.example および nonce xyz123456789 にバインドして、バインドされたトークンを保存します。

1.2.3. フォームの送信

ユーザーがフォームを送信すると、ブラウザーはバインドされたトークンを非表示の入力 フィールドに自動的に挿入します。検証者は次の POST ペイロードを受信します:

POST /signup HTTP/1.1
Host: rp.example
Content-Type: application/x-www-form-urlencoded

email=user%40email.example&evt=eyJhbGciOiJFZERTQSIsImtpZCI6IjIwMjQtMDgtMTkiLCJ0eXAiOiJldnQrand0In0...

検証者は次に evt トークンを解析して検証し(署名、オリジン rp.example、nonce xyz123456789、およびメール user@email.example の一致を検証します)、検証メールを送信することなく登録を完了します。

2. HTML の拡張

この仕様は、新しい自動入力フィールド名を導入し、 nonce 属性の使用を拡張することにより、HTML 標準 [HTML] を拡張します。

2.1. email-verification-token 自動入力値

email-verification-token キーワードが、[HTML] で定義される自動入力 フィールド名(具体的には、詳細トークン)の一覧に追加されます。

<input> 要素の autocomplete 属性が email-verification-token に設定されている場合、同じフォーム内でユーザーが メールアドレスを選択して検証していることを条件として、ユーザーエージェントはフォーム送信時にこのフィールドへ 暗号学的にバインドされたメール検証トークン(EVT)を入力するよう試みるべきであることを示します。

通常、このキーワードは <input type="hidden"> 要素で使用されます。

2.2. input 要素の nonce 属性

この仕様は、もともと [HTML]<script> および <style> 要素に対して定義され(コンテンツセキュリティポリシー [CSP] で使用される)、 nonce 属性を <input> 要素に拡張します。

autocomplete="email-verification-token" を持つ <input> 要素に指定された場合、 nonce 属性には、サーバー側で生成された暗号学的に強いランダム値( 暗号 nonce)が含まれます。

この nonce は、生成される EVT を特定のフォーム提示にバインドし、リプレイ攻撃を防ぐために使用されます。

nonce 属性の値は、ページをレンダリングするたびに一意でなければなりません。

3. ブラウザーの処理モデル

3.1. 自動入力の選択の処理

ユーザーが、<form> form 内の <input> 要素 emailInput に対するユーザーエージェントの自動入力候補から、メールアドレス email を選択した場合:

  1. form 内で、値が email-verification-token である autocomplete 属性を持つ最初の <input> 要素を evtInput とします。

  2. そのような evtInput が存在しない場合、これらの手順を終了します。

  3. evtInputnonce 属性の値を nonce とします。

  4. nonce が空の場合、これらの手順を終了します。

  5. form の EVP 状態を次のように設定します:

    • email: email

    • inputElement: emailInput

    • token: null

  6. バックグラウンドで、次の手順を実行します:

    1. email に対して [EVP-Protocol] で定義される 発行者の 発見 の手順を実行した結果を issuer とします。

    2. issuer が null の場合、これらの手順を終了します。

    3. emailissuer に対して アカウントの検証を実行した結果を accountMatch とします。

    4. accountMatch が false の場合、これらの手順を終了します。

    5. メールアドレス emailissuer で検証する許可を求めるユーザープロンプトを表示します。

    6. ユーザーが許可を拒否した場合、これらの手順を終了します。

    7. issuer から email に対する EVT の発行を実行した結果を evtResult とします。

    8. evtResult が null の場合、これらの手順を終了します。

    9. evtevtResult[0] とします。

    10. keyPairevtResult[1] とします。

    11. keyPair の秘密鍵コンポーネントを使用し、nonce と文書のオリジンを指定して、 evt に対して [EVP-Protocol] で定義される 鍵バインドの 作成 の手順を実行した結果を kbEvt とします。

    12. form の EVP 状態を state とします。

    13. state が null ではなく、stateemailemail と ASCII 大文字・小文字を区別せずに等しい場合:

      1. statetokenkbEvt に設定します。

3.2. フォーム送信との統合

<form> form が送信された場合:

  1. form の EVP 状態を state とします。

  2. state が null、または statetoken が null の場合、標準の フォーム送信手順を続行します。

  3. stateinputElement の値を currentEmail とします。

  4. currentEmailstateemail と ASCII 大文字・小文字を区別せずに等しい場合:

    1. form 内で、値が email-verification-token である autocomplete 属性を 持つ最初の <input> 要素を evtInput とします。

    2. evtInput が存在する場合:

      1. evtInput の値を statetoken に設定します。

  5. [HTML] で定義される標準のフォーム送信手順を続行します。

3.3. アカウントの検証

メールアドレス email と発行者ドメイン issuer が与えられた場合、ユーザーエージェントは アカウントを検証するために次の手順を実行しなければなりません:

  1. ログイン状態 API [login-status] を使用して、issuer のログイン状態を確認します。

  2. 状態が ログアウト済み の場合、 false を返します。

  3. [fedcm] で定義される、 issuerwell-known ファイルを取得した結果を wellKnown とします。

  4. wellKnown が null の場合、false を返します。

  5. wellKnownaccounts_endpoint メンバーの値を accountsEndpoint とします。

  6. accountsEndpoint が存在しないか、有効な URL ではない場合、false を返します。

  7. issueraccountsEndpoint に対して、 [fedcm] で定義される アカウントを取得するアルゴリズムを実行した結果を accounts とします。

  8. accounts が null または空の場合、false を返します。

  9. accounts 内の各 account について:

    1. accountemail メンバーの値を accountEmail とします。

    2. accountEmailemail と ASCII 大文字・小文字を区別せずに等しい場合、true を返します。

  10. false を返します。

3.4. EVT の 発行

メールアドレス email と発行者ドメイン issuer が与えられた場合、ユーザーエージェントは EVT を取得するために次の手順を実行しなければなりません:

  1. 一時的な非対称鍵ペア keyPair を生成します(発行者のメタデータで定義される、 発行者が対応するアルゴリズムを使用し、指定されていない場合は Ed25519 を既定値とします)。

  2. JSON Web Token [JWT] requestToken を構築します:

    1. ヘッダーには次のものを含めなければなりません:

      • alg: 署名アルゴリズム(keyPair のアルゴリズムと一致するもの)。

      • jwk: keyPair の公開鍵コンポーネント。

    2. ペイロードには次のものを含めなければなりません:

      • aud: issuer の識別子(ドメイン)。

      • iat: 現在時刻。

      • email: email アドレス。

    3. keyPair の秘密鍵コンポーネントを使用して requestToken に署名します。

  3. 発行者のトークン発行エンドポイント(発行者のメタデータから取得される)を issuanceUrl とします。

  4. issuanceUrl に対する HTTP POST 要求 request を構築します:

    1. Content-Type ヘッダーを application/x-www-form-urlencoded に設定します。

    2. Sec-Fetch-Dest ヘッダーを email-verification に設定します。

    3. issuer のファーストパーティ Cookie を含めます。

    4. 要求の本体を次の URL エンコードされた表現に設定します: request_token = requestToken(文字列として直列化)。

  5. request を送信し、応答 callResponse を待ちます。

  6. callResponse のステータスコードが 200 OK ではないか、その Content-Typeapplication/json ではない場合、null を返します。

  7. callResponse の本体を JSON として解析し、その結果を json とします。

  8. jsonissuance_token が含まれていない場合、null を返します。

  9. jsonissuance_tokenevt とします。

  10. evt を検証します:

    1. evt が、発行者によって署名された有効な SD-JWT [SD-JWT] であることを検証します。

    2. evt 内の cnf クレームに、keyPair の 公開鍵と一致する公開鍵が含まれていることを検証します。

    3. evt 内の email クレームが email と一致することを検証します。

  11. 検証に失敗した場合、null を返します。

  12. evt, keyPair)を含むタプルを返します。

4. 検証者の処理モデル

検証者が、メールアドレス email とバインドされたトークン boundTokenautocomplete="email-verification-token" を持つ入力フィールドから取得)を含む送信済みフォームを受信した場合:

  1. 検証者のオリジンと期待される nonce に対して、boundToken[EVP-Protocol] で定義される トークンの 検証 の手順を実行します。

  2. 検証に失敗した場合、検証を失敗させます。

  3. 検証済みトークンから抽出されたメールアドレスを verifiedEmail とします。

  4. verifiedEmailemail と ASCII 大文字・小文字を区別せずに等しくない場合、検証を失敗させます。

  5. それ以外の場合、検証は成功します。

5. セキュリティとプライバシーに関する考慮事項

5.1. プライバシー

5.1.1. 発行者のブラインド化

EVP の主要なプライバシー目標は、ユーザーがどの検証者と対話しているかを発行者が知ることを防ぐことです。

ユーザーエージェントは、Well-Known の取得および Accounts の取得によって検証者の オリジンが漏えいしないことを確保しなければなりません。 発行要求は資格情報を伴いますが、要求ヘッダーに検証者のオリジンを含めてはなりません (たとえば、Referer または Origin は省略しなければなりません)。

5.1.2. 追跡のリスク

発行要求では Cookie が使用されるため、発行者はユーザーがアクティブであることを知ります。ただし、これは ユーザーが検証のために自らメールを選択した場合にのみ知られるものであり、ユーザーが開始した操作です。

5.2. セキュリティ

5.2.1. リプレイ攻撃

提示トークン(EVT+KB)は、鍵バインド JWT を介して特定の nonce および audience(検証者の オリジン)にバインドされます。 検証者は次のことを検証しなければなりません:
  1. audience が自身のオリジンと一致すること。

  2. nonce が、フォーム提示用に生成したものと一致すること。

  3. exp クレームの有効期限が切れていないこと。

これにより、攻撃者が EVT+KB を傍受し、別のサイトまたは異なる コンテキストで再利用することを防ぎます。

5.2.2. DNS セキュリティ

発行者の発見は DNS TXT レコードに依存します。DNS が侵害された場合、攻撃者は発見先を 悪意のある発行者にリダイレクトできる可能性があります。 これを軽減するため、ユーザーエージェントはセキュア DNS(DNS-over-HTTPS または DNS-over-TLS)を使用し、利用可能な場合は DNSSEC 署名を確認するべきです。 さらに、発行者はメールドメインと一致しなければなりません(明示的かつ安全に委任されている場合を除きます)。

適合性

文書の 表記規則

適合性要件は、説明的な表明と RFC 2119 の用語を組み合わせて 表現されます。 この文書の規範的な部分におけるキーワード「MUST」、「MUST NOT」、「REQUIRED」、「SHALL」、「SHALL NOT」、「SHOULD」、「SHOULD NOT」、「RECOMMENDED」、 「MAY」、および「OPTIONAL」は、 RFC 2119 に記載されているとおりに 解釈されるものとします。 ただし、読みやすさのため、 この仕様ではこれらの単語をすべて大文字では表記しません。

明示的に非規範的と示された節、例、および注記を除き、 この仕様のすべてのテキストは規範的です。 [RFC2119]

この仕様の例は、「たとえば」という語で導入されるか、 class="example" を使用して 規範的なテキストから区別されます。 次のようになります:

これは参考情報としての例です。

参考情報としての注記は「注」という語で始まり、 class="note" を使用して 規範的なテキストから区別されます。 次のようになります:

注: これは参考情報としての注記です。

索引

この仕様で定義される 用語

参考文献

規範的参考文献

[EVP-Protocol]
Dick Hardt; Sam Goto. メール検証 プロトコル(EVP)バックエンド. インターネットドラフト. URL: https://www.ietf.org/archive/id/draft-hardt-email-verification-00.html
[FEDCM]
Nicolas Pena Moreno. 連合資格情報管理 API. URL: https://w3c-fedid.github.io/FedCM/
[LOGIN-STATUS]
ログイン状態 API. 編集者草案. URL: https://w3c-fedid.github.io/login-status/
[RFC2119]
S. Bradner. 要件レベルを 示すために RFC で使用するキーワード. 1997年3月. 現行の最良慣行. URL: https://datatracker.ietf.org/doc/html/rfc2119

非規範的参考文献

[CSP]
Mike West; Antonio Sartori. コンテンツセキュリティポリシー レベル 3. URL: https://w3c.github.io/webappsec-csp/
[HTML]
Anne van Kesteren; et al. HTML 標準. 現行標準. URL: https://html.spec.whatwg.org/multipage/
[JWT]
M. Jones; J. Bradley; N. Sakimura. JSON Web Token (JWT). 2015年5月. 標準化への提唱. URL: https://www.rfc-editor.org/info/rfc7519/
[SD-JWT]
D. Fett; K. Yasuda; B. Campbell. JSON Web Token の選択的開示(SD-JWT). RFC. URL: https://www.rfc-editor.org/rfc/rfc9682.html