🐕

OIDCにおけるセキュリティ対策が、脅威をブロックしている方法

に公開

OIDCのフローにおいては、セキュアな情報を盗まれてしまう懸念点があります。そのためにセキュアなプロトコルが存在しています。セキュリティ対策として何ができるのかをそれぞれ見ていきます。

OIDCフローのシーケンス

OIDCの簡略シーケンスを下記として定義します。

sequenceDiagram
  participant User
  participant UserAgent
  participant RP as Relying Party (Client)
  participant OP as OpenID Provider (Authorization Server)

  User ->> UserAgent: ①:アプリにアクセス
  UserAgent ->> RP: ②:認証が必要なリソースにアクセス
  RP ->> RP: ③-1:state を生成
  RP ->> RP: ③-2:code_verifier を生成
  RP ->> RP: ③-3:code_challenge = BASE64URL-ENCODE(SHA256(code_verifier))
  RP ->> UserAgent: ④:OPへのリダイレクト指示(/authorize?\n scope=openid\n response_type=code\n client_id=...\n redirect_uri=...\n state=xxx\n code_challenge=xxx\n code_challenge_method=S256)
  UserAgent ->> OP: ⑤:認可リクエスト送信
  OP ->> OP: ⑥-1:client_id, redirect_uri, scope 等の検証
  OP ->> User: ⑥-2:ログイン&同意画面
  User(UserAgent) ->> OP: ⑦:認証 & 同意
  OP ->> UserAgent: ⑧:リダイレクト(redirect_uri?code=xyz&state=xxx)
  UserAgent ->> RP: ⑨:認可コードとstateを送信
  RP ->> RP: ⑩:stateを検証
  RP ->> OP: ⑪:トークンリクエスト(/token\n grant_type=authorization_code\n code=xyz\n redirect_uri=...\n client_id=...\n code_verifier=元の値)
  OP ->> RP: ⑫:IDトークン + アクセストークン
  RP ->> RP: ⑬:IDトークン検証(ユーザー認証完了)
  RP ->> UserAgent: ⑭:トークンの付与

セキュリティコードの必要性

state

発行者:RP
検証者:RP
脅威:CSRFの脅威

OP ->> UserAgent: ⑧:リダイレクト(redirect_uri?code=xyz&state=xxx)する際に、RPは、OPから返ってきた認可コード(code)とstateが「自分が開始したリクエストに対する応答かどうか」を検証しないと、外部からの偽リクエストを処理してしまう可能性がある。

対策:

RP自身が発行したstateを事前に保存しておき、リダイレクト応答で受け取ったstateと一致するかを検証することで、「この認可応答が自分自身によるリクエストの結果である」ことを確認し、CSRFを防止する。

攻撃の流れ(state がない想定):

  1. 攻撃者は自分のブラウザでOPにログインして、自分用の認可コードを取得
  2. redirect_uri?code=attackerCode というURLを生成
  3. このURLをターゲット(被害者)に踏ませる(例:メールやサイトにリンクを埋め込む)
  4. ターゲットのブラウザがそのURLにアクセス
  5. RPは state 検証をしないので code=attackerCode を信用してトークン取得

結果:被害者のセッションが攻撃者のアカウントでログインされる

CSRFの脅威

https://zenn.dev/osachi/articles/132a0cbf957d6f

client_id(redirect_uri)

発行者:OPが発行(RPがredirect_uriの登録を申請し、OPがredirect_uriを登録、client_idを発行)
検証者:OP
脅威:

利用を許可していないredirect_uriにリダイレクトすること

対策:

事前に利用するRPのclient_id・redirect_uriをOPは保持しておきます。そうすることで、利用を許可していないredirect_uriにリダイレクトさせることを防ぎます。

code_verifier, code_challenge / PKCE

発行者:RP
検証者:OP(/token リクエスト時に code_verifier を使って検証する)
脅威:code injection attack

認可コードが中間者や悪意のあるアプリに盗まれた場合、そのコードを使ってトークンを取得されてしまう(code injection attack)に、無条件にtokenを発行してしまう。悪意のあるRPを判断することができない。

対策:

RPが事前に作成したcode_challenge、code_verifierのペアとなるデータを利用する。
> ④:OPへのリダイレクト指示(/authorize?\n scope=openid\n response_type=code\n client_id=...\n redirect_uri=...\n state=xxx\n code_challenge=xxx\n code_challenge_method=S256)
認可リクエスト時にcode_verifier・code_challenge_methodを送り
> ⑪:トークンリクエスト(/token\n grant_type=authorization_code\n code=xyz\n redirect_uri=...\n client_id=...\n code_verifier=元の値)
トークンリクエスト時にcode_verifierを送ることによって、認可リクエストを開始したRPとトークンリクエストしたRPが同一リソースであることを判定する。

codeがインジェクションされる可能性

codeを盗まれてしまうケースについて。

悪意あるリダイレクトURIへの送信(open redirect + client misconfiguration)

脅威:
攻撃者が不正な redirect_uri を OP に送り、そこに code を送らせることで code を盗む
対応:
OP 側で redirect_uri を完全一致で検証し、client_id ごとに事前登録された redirect_uri 以外は拒否

リダイレクト中の通信がHTTPSでない(中間者攻撃 / MITM)

脅威:
ネットワーク上で暗号化されてない平文でcodeが送られてしまう
対応:
redirect_uri を https に限定する(OP 側のポリシーでも enforce)+ トークンエンドポイントも含めすべて https にする

ログ / ブラウザ履歴 / リファラからの漏洩

脅威:
リダイレクトURLに含まれる code が、サーバーのアクセスログ、ブラウザの履歴、Referer ヘッダーなどに残り、他のスクリプトや中間者に読み取られる可能性がある

対策:
state と PKCE を併用

WebViewやカスタムURLスキーム使用時の誤実装

脅威:
モバイルアプリでは、WebViewや myapp://callback?code=xyz のようなカスタムスキームでリダイレクトを受けるケースがある。誤って複数アプリがそのスキームを登録していると、攻撃者アプリが横取りする可能性もある
対策:
カスタムスキームではなく OS 提供の App-claimed URI(例:App Links / Universal Links)を使う
state と PKCE を併用

Discussion