注意: この記事はLLMによって英語から翻訳されたものです。正確性については保証いたしかねますので、あらかじめご了承ください。英語の原文はこちら。
私はかなり長い間、二要素認証にYubikeyを使ってきたが、プロトコルレベルでどのように動作するのかを調べる機会がなかった。この記事ではそれについて解説する。
FIDO U2Fに馴染みがない方のために説明すると、これは物理的なセキュリティキーが「既存のユーザー名・パスワードベースのログインフローを強化する二要素として機能する」ための認証規格である。簡単に言えば、パスワード入力後にセキュリティキーをコンピュータに差し込み、必要に応じてタッチすることでログインを許可する仕組みだ(NFC版も存在する)。
なお、簡潔さとわかりやすさのために、いくつかの点を簡略化している(例えば、各やり取りにおけるブラウザの役割については説明していない)。詳細を知りたい場合は、Yubicoの非常に詳しいドキュメントページを参照してほしい。
デバイスの登録#
セキュリティキーをWebサイトの二要素認証として使うための最初のステップは、キーを登録することだ。以下の図はその手順を示している。

基本的に、U2Fトークンは(ECC)キーペアを生成する。次に、デバイスから決して外に出ないマスターキーを使って秘密鍵とApp IDを暗号化し、公開鍵とともにWebサイトに送信する。
秘密鍵を(暗号化されているとはいえ)送信するのは少し奇妙に思えるかもしれないが、これによりセキュリティキーはローカルストレージに依存する必要がなくなり、無制限の数のWebサイトで使用できるようになる。
図ではApp IDのみを示しているが、これは簡略化のためであり、このApp IDはWebサイトのURLやU2Fキーへのリクエストの発信元のようなものとして理解してほしい。
認証#
キーの設定が完了したので、Webサイトへのログイン時に二要素認証デバイスとして使用できるようになった。ログイン時に何が起こるかを以下の図に示す。

セキュリティキーを使用する際のワークフローを簡潔にまとめると以下の通りだ:
- U2Fキーはキーハンドル(登録フェーズで生成されたもの)を受け取り、マスターキーで復号して秘密鍵とApp IDを取得する。このプロセスにより、このWebサイトが確かに登録済みであることも確認できる
- U2Fキーにはローカルカウンターがあり、Webサイトでの認証のたびにインクリメントされる。これによりリプレイ攻撃を防ぐことができる。Webサイトは認証のたびに現在のカウンター値を保存し、それより低いカウンター値のレスポンスは破棄する
- 認証時に、クライアントはApp IDが現在接続しているWebサイトのアドレスと一致するかも確認する。これはフィッシング防止のためだ。第三者がメッセージを傍受しようとした場合、認証リクエストの発信元が異なるため、認証は進行しない
- 前のパートで説明した通り、WebサイトはU2Fトークンが登録フェーズで生成したECC公開鍵を保存している。U2Fキーはハンドルから取得したECC秘密鍵を使ってチャレンジ(ランダム)データやその他いくつかのフィールドに署名し、Webサイトは公開鍵を使ってデータが正しいデバイスによって署名されたことを検証できる
まとめ#
これでU2Fセキュリティキーの仕組みについて十分に理解できたはずだ。なお、このようなキーの実装はメーカーによって異なる場合がある。例えば:
- 認証に使うサービスごとにカウンターを持つこともできる(グローバルなカウンターではなく)
- ハンドルにECC秘密鍵を含める必要はない。トークンはサービスに一意のIDを送信し、どのECC秘密鍵がどのサービスに関連付けられているかをローカルに保存することもできる
参考文献#
- How FIDO U2F Works (Yubico)
- Key Generation (Yubico)
- U2F Specs (FIDO Alliance)
クレジット#
- カバー写真:regularguy.eth(Unsplash)