OAuth 2.0 とかに登場する state パラメーターってどう使えばいいんだっけ


  • クライアント側で生成して、なんやかんやリダイレクトされて戻ってきたらバックエンドなりクライアントで検証する
  • 例えばクライアント側で xxx という state を生成して保存しておいて、なんやかんやリダイレクトされてクライアントに戻ってきた際に付与されている state が xxx と同一かチェックすることで検証とする

OAuth 2.0 における state パラメーターとは

  • CSRF を防ぐためのパラメーター
  • セッションに紐づくアクセストークンであるか?を担保する
    • これがないと意図せず攻撃者のトークンを使ってしまい、攻撃者のリソースとして秘密の情報を投稿してしまう・・・といったリスクがある
    • まぁ最近は殆どの場合 OpenID Connect が使われており PKCE や nonce を使っていれば大した問題にはならないかもしれない

The OAuth 2.0 Authorization Framework
http://openid-foundation-japan.github.io/rfc6749.ja.html#CSRF

クロスサイトリクエストフォージェリ (CSRF) は, 攻撃者が犠牲となるエンドユーザーのユーザーエージェントに (例えば, ユーザーエージェントに誤解を招きやすいリンクやイメージ, 転送によって) 悪意のあるURIを閲覧させることにより (通常, 有効なセッションクッキーの存在によって) 信頼が確立されたサーバーへ接続させる手法である.

クライアントのリダイレクトURIに対するCSRF攻撃は, 攻撃者が自身の認可コードやアクセストークンを紛れ込ませることを可能とし, クライアントに犠牲者の保護されたリソースではなく, 攻撃者のリソースに紐付いたアクセストークンを使わせることが出来てしまう (例えば, 犠牲者の銀行口座情報を攻撃者の管理しているリソースへ保存してしまう, といったことも可能となる).

クライアントは自身のリダイレクトURIに対してCSRF保護対策を導入しなければならない (MUST). 一般的に保護対策は, リダイレクトURIのエンドポイントへ送られたすべての要求に対して, 要求とユーザーエージェントの認証状態を紐付けるための値を含めることにより実現する (例えば, ユーザーエージェントを認証するために使うセッションクッキーのハッシュなど). クライアントは認可要求の発行時, この値を認可サーバーへ伝搬するために state リクエストパラメーターを利用すべきである (SHOULD).

一旦エンドユーザーの認可が得られると, 認可サーバーはエンドユーザーのユーザーエージェントを state パラメーターに含まれる要求されたバインド値と共にクライアントへリダイレクトする. クライアントはバインド値とユーザーエージェントの認証状態を突合することによりリクエストの正当性を確認することが出来る. CSRFを防ぐために使用されるバインド値は ( Section 10.10 にて説明されている) 推測不能な値を含まねばならず (MUST), ユーザーエージェントの認証状態 (例えば, セッションクッキーやHTML5のローカルストレージ) はクライアントおよびユーザーエージェントのみがアクセスできる状態に保たれなければならない (つまり, 同一起源ポリシーによる保護) (MUST).

認可サーバーの認可エンドポイントへのCSRF攻撃はエンドユーザーに知られることなく, 攻撃者が悪意のあるクライアントへのエンドユーザー認可を取得可能にしてしまう.

認可サーバーは認可エンドポイントにCSRF保護を実装せねばならず, 悪意あるクライアントがリソースオーナーへの通知と明確な同意なく認可を取得出来ないことを保証せねばならない (MUST).

state パラメーターは具体的にどう使えば良い?

Auth0 が素晴らしいドキュメントを公開している

Prevent Attacks and Redirect Users with OAuth 2.0 State Parameters
https://auth0.com/docs/protocols/state-parameters#set-and-compare-state-parameter-values

大まかな手順

  1. リクエストを IdP にリダイレクトする前に、クライアント側でランダムな文字列を生成
  2. 生成したランダムな文字列をローカルに保存しておく
    • localstorage や cookie など
  3. 必要に応じて URL-encoding した上で state パラメーターを指定して Authorization Endpoint にリクエスト
  4. なんやかんやあって返された state パラメーターの値をクライアントで取得し、以前に保存したものと同一か比較
    • 一致すればレスポンスを許容し、一致しなけれ拒否する

state パラメーターとして使う文字列あれこれ

  • シンプルにはランダムな文字列で OK
    • セッションと紐づく暗号論的にセキュアな値、セッション Cookie のハッシュとか
    • UUIDv4 とかでも良さそう
  • state パラメーターとして、認証プロセスが開始する前のアプリケーション状態を扱う、といったこともできる
    • 例えば、ユーザーが保護されたページにアクセスする予定であり、そのアクションによって認証リクエストがトリガーされた場合、認証の終了後にその URL を保存して、ユーザーを目的のページにリダイレクトする、とか
    • 結局 state パラメーターは任意の文字列が使えるので、アプリケーション要件にからめて自由に使うことができる
    • 必要な任意の情報を JWT まとめちゃって使うとか

その他役立ちそうな情報

OAuth 2.0 Threat Model and Security Considerations
http://openid-foundation-japan.github.io/rfc6819.ja.html#link_state_uasession


Final: OpenID Connect Core 1.0 incorporating errata set 1
http://openid-foundation-japan.github.io/openid-connect-core-1_0.ja.html#AuthRequest