Single Page ApplicationでOpen ID Connect連携する際の検討事項 メモ

* Single Page Application(SPA)がOpen ID Connect(OIDC)連携する際に検討・考慮が必要な内容をメモする。
  * **SPA** : 単一のWebページでアプリケーションを構成する設計構造のこと。1つのHTMLに対してJavaScriptで動的に変更を加えながら画面描画を行う。
  * **OIDC** : OAuth 2.0を使ってID連携をする際に、OAuth 2.0では標準化されていない機能で、かつID連携には共通して必要となる機能(IDトークンとUserInfoエンドポイント)を標準化したプロトコルのこと。認可だけでなく、認証にも対応している。



## 認可コード横取り攻撃対策

* 認可コード横取り攻撃：悪意あるアプリが、認可コードを横取りし、クライアントの代わりにアクセストークンを発行する攻撃。
* **Authorization Code Flow + PKCE(Proof Key Code Exchange)**：認可コードフローに認可コード横取り対策を加えたもの。
  1. クライアントは、認可エンドポイントへ`code_challenge`(`code_verifier`と`code_challenge_method`(`code_challenge` の計算に用いるメソッド。`plain` (デフォルト) もしくは `S256`を指定する。)から計算された値)と`code_challenge_method`をつけて認可リクエストを行う。
  2. OIDCサーバーは、認可リクエストを処理する時に、生成した認可コードと共に `code_challenge`と `code_challenge_method` をDBに保存する。
  3. クライアントは、`code_verifier` (認可リクエストの際に渡した `code_challenge`の元となった値)をつけてトークンリクエストする。
  4. OIDCサーバーは、トークンリクエストから `code_verifier`を取り出し、その `code_verifier` とDBに保存した `code_challenge_method` を用いて `code_challenge` を計算し、計算結果がDBに保存しておいた `code_challenge`と等しいかどうかを検証する。
![authz_code_flow_with_pkce.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586535/c592bd04-c8d6-b3c6-53c5-9814701579dc.png)


## リプレイアタック対策

* リプレイアタック：ログイン時の送信データ(IDトークン)を攻撃者が記録し、それをそのまま再現することで不正にログインする攻撃。

* **`nonce`パラメータの利用**
  1. クライアントは、認可リクエスト時に`nonce`を生成しOIDCサーバーに渡す。
  2. OIDCサーバーは、IDトークン中に`nonce`を含める。
  3. クライアントは、自分の認可リクエストに対してのIDトークンであることを確認するため、リクエスト時に渡した`nonce`とIDトークンに含まれる`nonce`の一致を確認する。

## CSRF対策
* **`state`パラメータの利用**
  1. クライアントは、認可リクエスト時に`state`を生成しOIDCサーバーへ送信する。
  2. OIDCサーバーは、クライアントに認可コードを送信する際、リクエストで送られてきた`state`も付与する。
  3. クライアントは、`state`がリクエスト時の値と一致しない、もしくは渡されなかった場合にトークンリクエストを行わない。

## アクセストークン漏洩対策

* アクセストークンを奪われた場合、APへの不正アクセスを発生させないようにする。
* **[DPoP(Demonstration of Proof-of-Possession at the Application Layer)](https://qiita.com/TakahikoKawasaki/items/34c82fb5c0595b6fc289)**
  * アクセストークンを提示しているクライアントがアクセストークンの正当な所有者か（＝アクセストークンの発行を受けたクライアントと同一か）を検証する。

## トークンの安全な管理

* SPA(ブラウザ)では、アクセストークンやIDトークンを安全に保管できない。
  * Web Storage(localStorage、SessionStorage)
     * XSSの危険あり(JSからアクセス可能なため)
  * Cookie
     * `httpOnly`、`secure`属性など必須(JSからアクセスさせないため)

* 結局、ベストプラクティスがわからない...以下のような対策もある模様。
  * [認可コードフロー＋独自セッション](https://speakerdeck.com/d_endo/30fen-deopenid-connectwan-quan-nili-jie-sitatoyan-eruyouninarumian-qiang-hui?slide=117)
     * OIDCをログイン管理に利用しない。
         * OIDCは認証のみに利用する。
         * RPのF/EとB/E間で独自のセッション(cookie)を構築し、ログイン管理を実施する。

## リフレッシュトークン横取り対策
* 攻撃者に使用済みリフレッシュトークンを奪われた際、攻撃者に新しいトークンを発行されないようにする。
* **[リフレッシュトークン ローテーション](https://speakerdeck.com/d_endo/30fen-deopenid-connectwan-quan-nili-jie-sitatoyan-eruyouninarumian-qiang-hui?slide=126)**
  * 古いリフレッシュトークンを使用して新しいリフレッシュトークンを発行する場合、
     * 古いリフレッシュトークンを無効化し、新しいリフレッシュトークン発行する。

    

## 参考情報

* [Using OpenID Connect for Single Page Applications](https://www.ubisecure.com/single-sign-on/single-page-application-and-openid-connect/)
* [30分でOpenID Connect完全に理解したと言えるようになる勉強会](https://speakerdeck.com/d_endo/30fen-deopenid-connectwan-quan-nili-jie-sitatoyan-eruyouninarumian-qiang-hui?slide=114)
* [SPA + OAuth 2.0 / Open ID Connect (OIDC) + API (Microsrvices)を実装する際に注意したいこと](https://tworks55.hatenablog.com/entry/2020/05/06/135107)
* [OpenID Connectのstateとnonceの違いがわからなかった](https://qiita.com/m28/items/10c3a1de1bdcfda874b1)