OpenID ConnectのImplicit Flow利用時のなりすまし攻撃対策を考える

# はじめに
はじめまして、[yuasa](https://melonattacker.github.io/)です。

本記事は、[Digital Identity技術勉強会 #iddance Advent Calendar 2023](https://qiita.com/advent-calendar/2023/iddance)の20日目の記事です。

本記事では、OpenID ConnectのImplicit Flowを利用する際に生じるなりすまし攻撃について説明し、既存の対策手法を説明した後に、FIDOを併用する対策を提案します。

# Implicit Flow利用時におけるなりすまし攻撃
対象ユースケースとして、IDトークンをブラウザ経由で受け取り、Relying Party (RP) におけるユーザ登録・ログインのためにRPのバックエンドにIDトークンを送信するケースを考えます。IDトークンをブラウザ経由で受け取る認証フローとしてはImplicit Flow（`response_type=id_token`）を想定します。RPにおけるログインでは、RPはIDトークンのみを用いてユーザを認証する。

![id_token_flow_register.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326169/6497e906-17f3-9807-9cf9-c023efe33fd8.png)

このユースケースにおいて、攻撃者が正規ユーザのIDトークンを取得可能な場合に、正規ユーザとしてログインを行うなりすまし攻撃が可能になります。

例えば、攻撃者は中間者攻撃、XSS（クロスサイトスクリプティング）などが可能な場合に正規ユーザのIDトークンを不正に取得することができ、それを同じRPに再送することで正規ユーザになりすませる可能性があリます。また、窃取したIDトークンを同じ[`aud`](https://openid-foundation-japan.github.io/openid-connect-core-1_0.ja.html)を持つIDトークンを許可するRPに送信することでなりすましができます。仕様には`aud`に`他のオーディエンスの識別子を含んでもよい（MAY）`との記述があるため、このような状況は起こりえます。

そして、攻撃者が正規ユーザのIdP認証情報を窃取できる場合にもIDトークンを発行し、それを使用してなりすましを行えます。また、OpenID Connectにおいてはthe end of the gameな状況ですが、IdPを侵害して署名鍵を窃取できる場合に、正規ユーザの識別子を[`sub`](https://openid-foundation-japan.github.io/openid-connect-core-1_0.ja.html)としたIDトークンを作成してなりすましを行えます。このようななりすましが可能になる原因は、RPがIDトークンのみを用いてユーザを検証することにあります。

<img width="400" alt="impersonation.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326169/c3487b30-4749-c95e-f899-1a5e589e0c5c.png">

まとめると、以下のなりすまし攻撃のパターンが存在しています。
- 正規ユーザのIDトークン窃取・使用（同じRP）
- 正規ユーザのIDトークン窃取・使用（同`aud`のIDトークンを許可する別RPに送信）
- 正規ユーザのIdP認証情報窃取・使用
- IdP署名鍵の窃取・使用

# 既存のなりすまし攻撃対策
既存のなりすまし攻撃対策としては、OpenID Connectにおける[nonceを用いた対策](https://openid-foundation-japan.github.io/openid-connect-core-1_0.ja.html#IDToken)、[Openpubkey](　https://eprint.iacr.org/2023/296)などがあります。

まず、[nonceを用いた対策](https://openid-foundation-japan.github.io/openid-connect-core-1_0.ja.html#IDToken)はIDトークンに含まれるnonce値を検証することで、再送攻撃を防ぐものです。RPはAuthentication Requestで送信したnonce値と受け取ったIDトークンに含まれるnonce値が一致することを検証します。この対策では同じRPへのIDトークンの再送攻撃を防ぐことができますが、同`aud`のIDトークンを許可する別RPへの再送攻撃は防ぐことができません。また、IdP認証情報の窃取によるなりすまし攻撃やIdP署名鍵の窃取によるなりすまし攻撃も防ぐことができません。

[Openpubkey](　https://eprint.iacr.org/2023/296)はIDトークンに公開鍵を紐づけることでProof-of-Possession（所有証明）機能を提供するOpenID Connectの拡張プロトコルです。ユーザはIDトークンの発行前に一時的な秘密鍵・公開鍵を作成し、IDトークンの発行時にユーザの公開鍵がnonce値に格納されます（これはPKトークンと呼ばれます）。RPはユーザが秘密鍵を用いて作成した署名をPKトークンとともに検証することで、IDトークンの再送攻撃を防ぎます。

ここで、攻撃者が正規ユーザのIdP認証情報を知っている場合に自身の秘密鍵・公開鍵を正規ユーザのIDトークンに紐づけることでなりすましを行うことが考えられます。これ対しては、ユーザ認証をIdPだけではなく追加のパーティでも行うMFA-cosignerという機能を用いることで、攻撃者が正規ユーザのIdP認証情報やIdP署名鍵を知っていたとしても、なりすましを行うことを防ぐことができます。しかし、攻撃者がユーザの端末を侵害可能な場合にユーザの秘密鍵を用いて有効な署名を作成することができ、その場合にはなりすましが可能となります。つまり、OpenpubkeyではIdPの他に認証を行う追加のパーティが必要となり、ユーザの端末が侵害された場合になりすましを防ぐことができないという課題が残ります。

|対策手法  | 正規ユーザのIDトークン窃取・使用（同じRP）への耐性 | 正規ユーザのIDトークン窃取・使用（同`aud`のIDトークンを許可する別RPに送信）への耐性 |正規ユーザのIdP認証情報窃取・使用への耐性 | IdP署名鍵の窃取・使用への耐性 | ユーザ端末の侵害への耐性 |　追加パーティの有無|
|---|---|---|---|---|---|---|
|nonceを用いた対策  | ○ | × | × | × | - | なし |
|Openpubkey（MFA-cosigner未使用）  | ○ | ○ | × | × | × | なし |
|Openpubkey（MFA-cosigner使用）  | ○ | ○ | ○ | ○ | × | あり |


# FIDOを用いたなりすまし攻撃対策
本記事で提案するなりすまし攻撃対策は、IDトークンの送信時にFIDO認証を併用するものです。

まず、ユーザ登録フェーズでIDトークンを送信する際に、IDトークンの`email`クレームを用いてメールアドレスの所有確認を行います。メールアドレスの所有確認が完了すると、ユーザはWebAuthnを用いたブラウザ側での処理で秘密鍵・公開鍵を生成し、秘密鍵をFIDO認証器に保存、公開鍵をRPに送信します。メールアドレスの所有確認により、攻撃者が自身の秘密鍵・公開鍵を正規ユーザのIDトークンに紐づけることを防ぎます。

![method1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326169/3f6c816d-fb3c-7b86-0bce-d147c3ab5f41.png)

次に、ユーザ認証フェーズでは指紋等のジェスチャ入力をユーザに要求し、ジェスチャ入力が完了すると秘密鍵を用いた署名を生成し、IDトークンとともに送信します。RPでは保存しておいた公開鍵を用いて署名を検証することで、攻撃者による正規ユーザのIDトークンを用いたなりすましを防ぎます。

また、本対策手法のPoCはこちらで実装しています。
https://github.com/melonattacker/oidc-access-control

# 既存の対策手法との比較
[Openpubkey](　https://eprint.iacr.org/2023/296)では追加のパーティによる認証（MFA-cosigner）により、攻撃者が正規ユーザのIDトークンに自身の秘密鍵・公開鍵を紐づけることを防いでいましたが、本対策手法ではIDトークンの`email`クレームを利用したメールアドレス所有確認により、認証を行うパーティを追加することなく防ぐことができます。

また、[Openpubkey](　https://eprint.iacr.org/2023/296)ではユーザの端末が侵害された場合に秘密鍵を用いて有効な署名が作成可能であるため、なりすましが可能となってしまいます。一方、本対策手法ではFIDOを用いているため、秘密鍵を用いて署名を作成するにはジェスチャ（指紋認証等）を行う必要があり、端末を侵害したとしてもなりすましを行うことはできません。

本対策手法では、Openpubkey（MFA-cosignerあり）と同様に、IDトークンの窃取による同じRPへの再送攻撃、同`aud`のIDトークンを許可する別RPへの再送攻撃、IdP認証情報の窃取によるなりすまし攻撃を防ぐことができます。しかし、IdP署名鍵の窃取によるなりすまし攻撃については、`email`クレームを攻撃者のメールアドレスに、`sub`クレームを正規ユーザの識別子としたIDトークンを発行し、登録の際に使用することで、RPへの登録が完了していないユーザについては自身の秘密鍵・公開鍵を紐づけることができてしまいます。一方、すでにRPへの登録が完了しているユーザについては、ログインにおけるなりすましを行うことはできません。

|対策手法  | 正規ユーザのIDトークン窃取・使用（同じRP）への耐性 | 正規ユーザのIDトークン窃取・使用（同`aud`のIDトークンを許可する別RPに送信）への耐性 |正規ユーザのIdP認証情報窃取・使用への耐性 | IdP署名鍵の窃取・使用への耐性 | ユーザ端末の侵害への耐性 |　追加パーティの有無|
|---|---|---|---|---|---|---|
|nonceを用いた対策  | ○ | × | × | × | - | なし |
|Openpubkey（MFA-cosigner未使用）  | ○ | ○ | × | × | × | なし |
|Openpubkey（MFA-cosigner使用）  | ○ | ○ | ○ | ○ | × | あり |
|本対策手法  | ○ | ○ | ○ | △（未登録ユーザへのなりすましが可能） |○ | なし |

# Authorization Code Flow使えば良くない？
Authorization Code Flowを利用すると、RPはIDトークンをIdPから直接受け取るため、窃取したIDトークンの再送攻撃は不可能となります。しかし、同`aud`のIDトークンを許可する別のRPへの再送攻撃や正規ユーザのIdP認証情報窃取によるなりすまし攻撃、IdPが侵害された場合のなりすまし攻撃は依然として可能であるため、なりすまし攻撃の対策を検討することはAuthorization Code Flowを利用する上でも必要であると考えられます。

# おわりに
本記事では、Implicit Flow利用時のなりすまし攻撃対策手法としてFIDOを併用することを提案しました。OpenID ConnectのImplicit Flow利用時には様々ななりすまし攻撃のパターンが考えられるため、より安全なソーシャルログイン機能提供のためにこのような対策を検討することは良いことだと思っています。

本記事+αな内容を1月の[OpenID Summit Tokyo 2024](https://www.openid.or.jp/summit/2024/)で発表します。このイベントに参加される方は、もし興味があれば自分の発表を聞きに来ていただけると幸いです。


# 参考文献
- https://openid-foundation-japan.github.io/openid-connect-core-1_0.ja.html#IDToken
- Heilman, Ethan, et al. "[OpenPubkey: Augmenting OpenID Connect with User held Signing Keys.](https://eprint.iacr.org/2023/296)" Cryptology ePrint Archive (2023).