ウォレットのVC提示でログインするには|使い回し・QR先読みを防ぐ確認の流れ
約12分で読めます
約12分
目次(タップで折りたたみ)
ある会社の業務サービスに、ウォレットで社員証の証明書(VC)を見せてログインする仕組みを入れることになりました。有効な社員証を見せた人は、そのまま管理画面に入れてよいのでしょうか。
設計を任された担当者が考えると、危ない場面がいくつも浮かびます。その提示データが、以前に別のログインで使われたものを攻撃者が送り直しただけだったら。署名は正しいので、そのまま通ってしまうかもしれません。別の端末でQRを読むログインなら、QRを他人に先に読まれることもあります。
ウォレットのロックを外して署名できた、というだけでは分からないことがあります。その証明書が本物の発行元から出たものか。今も失効していないか。サービスの利用条件に合うか。逆に、本物で有効な証明書を受け取っても、その人がどの会員アカウントの持ち主か、管理画面まで触ってよいかは、別に確かめる必要があります。
だから、利用者の画面は一続きでも、裏側では次の5つを別々に確かめます。そして、5つの結果を同じ1つのログイン要求に結び付けます。
- ウォレットの操作(利用者が端末で承認したか)
- 証明書の検証
- アカウントの特定
- 業務の認可(その画面を使ってよいか)
- セッションの発行
以下では、Webサービスがウォレットに証明書の提示を求め、確かめた結果でログインのセッションを出す構成を、順に組み立てます。VCの基礎は「Verifiable Credentialsとは」、発行者・所持者・検証者の責任分界を含む全体設計は「DID・VCの導入設計」で解説しています。
この記事で使う言葉
- 発行者・所持者・検証者:証明書を出す組織(Issuer)・ウォレットに入れて持つ人(Holder)・受け取って確かめるサービス(Verifier)
- nonce:その要求専用の、一度きりの使い捨ての値
- state:ブラウザからの要求と、返ってきた応答を結ぶ札
- 所持者との結び付き(holder binding):証明書に結び付いた鍵を持つ人が提示したことの確認
- IdP:ログインを受け持ち、セッションを出す認証の基盤
「ウォレットを操作できた」と「ログインさせてよい」は別の確認
5つの確認は、それぞれ別の事実を確かめます。どれか1つだけでは決まらないことがあります。
| 確認 | 確認する事実 | 単独では決まらないこと |
|---|---|---|
| ウォレットの利用者認証 | 鍵の利用を端末上で承認した | 属性の正しさ、業務権限 |
| 証明書の検証 | 署名、要求との対応、期限、状態、発行者の信頼 | 既存アカウントとの対応 |
| アカウントの特定 | 提示結果をサービス内の主体へ対応付けた | その操作への許可 |
| 業務の認可 | 主体、役割、対象リソース、状況がログインを許す条件を満たす | 証明書の暗号的な有効性 |
| セッション発行 | 上記の結果を短寿命のセッションへ変換した | 将来も証明書が有効であること |
それぞれを誰が担うかは、後半の「実装する人向けの詳細」にまとめています。ウォレットの利用者認証にパスキーを使う設計は「PasskeyとWebAuthnを使うWallet設計」で扱っています。
OpenID for Verifiable Presentations(OpenID4VP)1.0 Finalは、証明書の提示を求めて、提示データ(Presentation)を受け取るための仕様です。受け取った結果(vp_token)は、アクセストークン(Access Token)ではありません。確かめた結果からサービスのセッションを出すのは、検証者の側の責任です。これを設計ではっきりさせておきます。
ログインの流れを6つの段階に分け、1つの番号で結ぶ
- 要求を作る:サービスは、利用目的、必要な証明書の種類と属性(claim)、保持の方針、
nonce、要求の期限、戻り先を確定します。 - ウォレットを呼び出す:同じ端末で完結する場合(same-device)は、アプリへのリンクやDigital Credentials API(ブラウザからウォレットを呼ぶ仕組み)を使います。別の端末を使う場合(cross-device)は、QRなどを使います。呼び出し方と証明書の形式は、別のものとして扱います。
- ウォレットで選び、同意する:ウォレットは、要求しているサービスと、見せる項目を表示します。利用者の認証の後、対象の証明書から提示データを作ります。利用者が取り消すのは失敗ではなく、はっきりした終わり方の一つです。
- 提示データを確かめる:検証者は、応答と要求の対応、
nonce、署名、所持者との結び付き、期限、状態、スキーマ、発行者の信頼、求めた属性との一致を確かめます。 - 誰か、何をしてよいかを決める:証明書の中身を見て、どの会員アカウントの人かを決めます。そのうえで、その人がこの画面を使ってよいかを確かめます。
- セッションを出す:認証した時刻、証明書の保証の水準、ログインを許す条件の版を含む、短い寿命のセッションを作ります。以後は提示データを使い回さず、通常のセッション管理に移ります。
後から調べられるよう、すべての段階に同じ取引の番号を付けます。ただし、同じ番号を外に出し続けると、他社のサービスと突き合わせて、その人の行動をたどられるおそれがあります。そこで、ブラウザのセッション、ウォレットへの要求、検証の処理、監査記録の番号は、内部の対応表で結びます。こうすれば、自社のログは後から追える一方で、異なる検証者の間で突き合わせる手がかりは増やしません。
古い提示データの送り直しを、どう防ぐか
冒頭の心配の一つめです。署名が正しくても、古い提示データを別のセッションで送り直せるなら、ログインを奪われます。
防ぐ鍵は、要求ごとに「一度きり」の記録を作ることです。要求を作るとき、推測できないnonceを発行します。あわせて、ブラウザの要求と応答を結ぶstateに当たる値、検証者の識別子、求めた属性、作った時刻、期限、使ったかどうかを保存します。
確かめた結果が成功でも失敗でも取消でも、その要求は終わった状態にします。同じ応答を、二度セッションに交換することはしません。要求の状態の移り方は、後半の表にまとめています。
別の端末でQRを読むとき、何に気をつけるか
冒頭の心配の二つめです。別の端末を使う場合、QRを読み取った端末と、ログインを始めたブラウザは別々です。そこで、次のように設計します。
- ブラウザに、応答を無期限に待たせて問い合わせ(ポーリング)させない。有効期限を短くし、問い合わせの間隔を決める。
- 終わった取引は一度きりにし、別のブラウザが結果を受け取れないようにする。
- QRには証明書や個人の属性を入れない。署名済みの要求か、寿命の短い参照先だけを入れる。
証明書に書かれた識別子を、そのままユーザーIDにしない
証明書の主体(Subject)や所持者の識別子は、発行者、証明書の種類、ウォレット、提示のしかたによって変わることがあります。1つの文字列だけで既存のユーザーに自動で結び付けると、別人を同じ人として扱う危険があります。たとえば次のような場合です。
- 別の発行者の証明書に、たまたま同じ値がある
- 再発行で識別子が変わった
- 家族や代理人が持つ証明書を見せた
初めて登録するときは、次のことを確かめます。信頼する発行者か、証明書の種類と保証の水準、主体と所持者の関係。そして既存のアカウントでもう一度認証してもらいます。確かめたうえで、サービス内部のアカウントと、確かめた属性の対応を、紐付けの記録として保存します。
2回目以降も、署名済みの変わらない識別子だけには頼りません。発行者の信頼、証明書の状態、対象の業務でログインを許す条件を、あらためて評価します。
年齢条件のように本人の名前が要らない処理では、生年月日を受け取って保存するより、「18歳以上」などの必要最小限の判定を求めます。選択的開示の要求設計は「年齢・資格証明の選択的開示設計」で詳しく扱っています。
失敗したとき、利用者に何を見せるか
失敗を「ログインできません」の一言にまとめず、失敗の種類ごとに、回復の方法を分けて見せます。
| 失敗 | サービス側の扱い | 利用者への表示 |
|---|---|---|
| ウォレットがない・非対応 | 要求の前または呼び出し時に判定 | 対応環境と代わりの認証方法を案内 |
| 利用者が取消 | 拒否(DENIED)で終了 | 失敗と断定せず、選び直せるようにする |
| 要求した証明書がない | セッションを発行しない | 必要な証明書と取得の経路を表示 |
| 署名・nonceの不一致 | 止めて、再利用を遮断 | 新しい要求からやり直す |
| 期限切れ・失効 | 対象の条件に従って拒否 | 更新・再発行への案内 |
| 状態を取得できない | リスクに応じて止めるか、限定的に処理 | 一時的な障害と再試行の時刻 |
| 検証は成功・アカウント未登録 | 自動で既存アカウントへ結合しない | 新規登録または安全な紐付けへ |
運用で見張る指標は、後半にまとめています。
確かめた結果の細かい理由をブラウザにそのまま返すと、攻撃者に手がかりを与えることがあります。その人が登録済みかどうかや、何を信頼しているかが分かってしまうからです。画面では、回復に必要な範囲まで一般的な表現にします。
監査ログには、機密である証明書の本文は残しません。残すのは、理由のコード、発行者、証明書の種類、条件の版、依存先、関連付けのIDです。証明書の失効情報を配る仕組みは「VCの失効設計」を参照してください。
ブロックチェーンは要るか
このログインの流れは、ブロックチェーンがなくても作れます。通常のPKI、署名付きのメタデータ、信頼リスト、状態情報の配信、既存のIdPとデータベースで足ります。
採用するかは、独立した複数の組織が、1つの管理者を信頼せずに同じ更新履歴を確かめる必要があるかで判断します。証明書の本文、秘密鍵、nonceやセッションは、どの場合も置きません。データごとの置き場所は後半の表にまとめています。
公開の台帳に個人の属性のハッシュを置いても、入力が正しいことや本人であることは保証されません。値の候補が少なければ、ハッシュから元の値を当てられるおそれもあります。従業員が使うウォレットの端末交換・紛失・退職の運用は「企業向け証明書ウォレットの運用設計」を参照してください。
本番の前に、重複・遅れ・別端末を試す
- 同じ提示データを並行して2回送っても、セッションが1つだけ発行される。
- 期限切れのnonce、別の検証者向けの応答、書き換えたstate、別のブラウザの取引を拒否する。
- 同じ端末でウォレットから戻ったとき、ログインを始める前の外部URLへ飛ばさない。
- 別端末用のQRを別人が先に読み取っても、元のブラウザが無条件にセッションを受け取らない。
- 状態確認のサービスがタイムアウトしたとき、管理画面とリスクの低い閲覧で、別々の条件が意図どおり働く。
- 確かめた後、アカウントの紐付けの失敗やセッション保存のタイムアウトが起きても、送り直しで誤った結び付けや二重発行をしない。
- 証明書の本文を、アプリケーションのログ、性能監視(APM)、アクセス解析、URL、QRに残さない。
- ウォレット非対応、取消、証明書不足から、代わりの認証方法か安全な再試行へ戻れる。
受け入れの指標は、ログインの成功率だけにしません。次のように分けて測ります。
- ウォレット呼び出しの成功率、同意の取消率、証明書の不足率
- 理由別の拒否率、状態確認の依存先の遅れ
- セッション交換で重複を止めた数、復旧にかかった時間
個人の属性を集計の軸に直接使わず、証明書の種類やエラーの理由を、種類の少ないコードで見張ります。
PoCは「ログインできた」で終わらせず、運用で困らないかまで確かめる
最小のPoCでも、次のものは通します。
- 同じ端末と別端末の、少なくとも一方
- 1種類の証明書
- 取消・期限切れ・状態を取得できない場合
- 初回の紐付けと、再ログイン
- ログアウトと、セッションの失効
暗号の検証ライブラリが成功したところで終えません。ログインを許す条件の版の管理、監査、代わりの認証方法、問い合わせを受けたときの調べ方まで確かめます。
実装する人向けの詳細
ここからは、要求・検証のAPIとセッションの交換を作る担当者向けに、分担・状態・監視・データの置き場所をまとめます。
5つの確認の主な実行主体
- ウォレットの利用者認証:ウォレット・端末
- 証明書の検証:検証者(Verifier)
- アカウントの特定:認証基盤・アカウントDB
- 業務の認可:業務API・認可基盤
- セッション発行:IdP・Webアプリ
識別子と紐付けの項目
すべての段階へ同じtransaction_idを付け、ブラウザのセッション、ウォレットへの要求、検証ジョブ、監査記録のIDを内部の対応表で結びます。証明書のcredentialSubjectや所持者の識別子を、そのままユーザーIDにしません。初回登録で確認した結果は、サービス内部のaccount_idと検証済み属性の対応として紐付け記録へ保存します。
証明書提示の取引の状態
| 状態 | 確定した事実 | 許可する次の処理 | 再送時の扱い |
|---|---|---|---|
要求済み(REQUESTED) | 要求内容、nonce、期限を保存 | ウォレットの呼び出し | 同じ要求を返すか、新規に採番 |
提示済み(PRESENTED) | 応答を受け取り、検証ジョブを開始 | 暗号・状態・判定方針の検証 | 同じ応答を再検証せず、結果を照会 |
検証済み(VERIFIED) | 検証結果と判定方針の版を保存 | 一度だけセッションへ交換 | 既存のセッションIDを返さない |
拒否(DENIED) | 取消または不合格の理由を分類 | 必要なら新規に要求 | 再利用不可 |
期限切れ(EXPIRED) | 期限超過 | 新規に要求 | 再利用不可 |
交換済み(CONSUMED) | セッションへ交換済み | 通常のセッション管理 | 監査記録だけを残す |
失敗ごとの運用・監視
- ウォレットがない・非対応:端末・方式別の到達率
- 利用者が取消:取消率。属性不足と区別
- 要求した証明書がない:発行サービスの障害と区別
- 署名・nonceの不一致:セキュリティ上の事象として関連付け
- 期限切れ・失効:発行者・状態の配信先別に監視
- 状態を取得できない:キャッシュの経過時間と依存先の目標値
- 検証は成功・アカウント未登録:誤った結合・重複アカウントを監査
データの置き場所
| データ | 原則の配置 | 理由 | ブロックチェーンの候補 |
|---|---|---|---|
| 証明書の本文・開示した属性 | ウォレット、暗号化した検証者の処理領域 | 目的の制限、最小化、削除が必要 | 置かない |
| 秘密鍵・ウォレットの起動に使う情報 | 端末の安全な保管領域、KMS/HSM | 取り出し・公開を防ぐ | 置かない |
| nonce、セッション、提示履歴 | 短寿命のキャッシュ、認証DB、監査基盤 | 高頻度・機密・失効が必要 | 置かない |
| 発行者の鍵・信頼情報 | PKI、署名付きのメタデータ、信頼レジストリ | 検証者が真正性を確認する | 複数の組織が共同管理するなら候補 |
| 失効・停止の状態 | 状態確認サービス、配布できるステータスリスト(失効状態をまとめて配る一覧) | 鮮度、可用性、プライバシーが必要 | 機密でない参照・コミットメントのみ候補 |
XTELAができること
私たちは、ウォレット/VCと既存のIdP・業務APIをつなぐ要件整理から、OpenID4VPの要求・検証API、アカウントの紐付け、状態遷移、再送や別端末を想定した障害試験まで、PoCと実装仕様として設計・開発しています。貴社の既存ログインを残したまま、1種類の証明書で「ログインしてよいか」を判定する経路を追加する形から始められます。技術構成の整理はお問い合わせからご相談ください。
主要参考資料
- OpenID for Verifiable Presentations 1.0 Final(2025年7月9日)
- OpenID Connect Core 1.0 incorporating errata set 2
- W3C Verifiable Credentials Data Model v2.0(W3C Recommendation、2025年5月15日)
- W3C Web Authentication: Level 3
- NIST SP 800-63C-4: Subscriber-Controlled Wallets
- デジタル庁 行政機関におけるVC・DIWの活用にあたる検討事項リスト(案)
資料の確認日と注意
OpenID Foundation、W3C、NIST、デジタル庁の一次資料は2026年9月24日に確認しました。一般的な技術・運用設計の解説であり、本人確認義務・個人情報の利用目的・証明の法的効力に関わる判断は、弁護士と連携して確認してください。