🔐

OAuth2.0におけるstate(CSRF対策)とPKCEの違い

2024/04/14に公開

※本記事はOAuth2.0のフローを理解している人向けの記事です。

先日仕事で、とある外部APIのアクセストークン発行までのAPI設計書を書いていました。
そこで、こんな疑問が浮かびました。

CSRFって、退会とか送金とか実行によって被害者が直接被害に遭うようなAPIを実行させる攻撃だよな...?なんで認可フローで対策する必要があるんだ...?」
CSRFOAuth PKCEってやってること似てね...?これどっちもやる必要ある...?」

...と。

なので今回はOAuth2.0での二つの働きとその違いについて調べてみました。
個々の詳しい説明は他の素晴らしい記事を参照してください。

結論

それぞれ違う攻撃の対策なのでどっちも必要。

それぞれの説明

フロー

CSRF

1.ランダムな文字列を生成し、サーバのDB、またはクライアントの(一時的な情報のため)セッションなどでstateとして保持。
2. 認可サーバへの認可コードリクエストのリクエストパラメータstateに、ランダムな文字列を付与し実行。
4. 認可サーバのレスポンスによりクライアントが任意のURLにリダイレクトする。
5. サーバはリダイレクト先のクエリパラメータにあるstateと、保持していたstateの値が一致していることで、通信の正当性を確認する。

PKCE

  1. 以下の条件を満たす文字列を生成し、code_verifierとしてサーバまたはクライアントに保持。
    アルファベット、数字、-、.、_、~から成り、43~128文字
  2. 事前に選定したcode_challenge_methodcode_verifierをハッシュ化。
  3. 認可サーバへの認可コードリクエストのリクエストパラメータcode_challengeに、生成したハッシュを付与し実行。
  4. 認可サーバはcode_challengeを保持。
  5. (認可リクエストのレスポンスはフローに関係ないので飛ばす)
  6. 認可サーバへのトークン取得リクエストのリクエストパラメータcode_verifierに、保持していた同名の文字列を付与し、同様にcode_challenge_methodを付与して実行。
  7. 認可サーバはハッシュ化に使用したcode_challenge_methodを元に保持するcode_challengeをデコードし、code_verifierと一致する文字列が取得できることで、通信の正当性を確認する。

特徴

CSRF

  • 認可コードリクエスト実行者と認可コードのレスポンスを受け取った人物が違うことを検知する
  • 生成した生の文字列を利用すること。
  • 認可コード取得のタイミングで検証すること。
  • サーバ側で検証すること。

PKCE

  • 認可コードリクエスト実行者とトークン取得リクエスト実行者が違うことを検知する
  • 生成した文字列をハッシュ化して利用すること。(しない場合もある)
  • トークン生成のタイミングで検証すること。
  • 認可サーバ側で検証すること。

弾くことのできる脅威とその攻撃シナリオ

CSRF

弾く攻撃 攻撃による被害
攻撃者のリソース(外部APIを通して利用できる外部のリソース)が、被害者のアプリに紐づく。 被害者がアプリにリソースを登録した場合、攻撃者の外部リソースに保存される。

想定される攻撃シナリオ

  1. 攻撃者は自身で認可コードリクエストを実行し、リダイレクトURLのリソース読み込み時点でフローを中断する。
  2. 認可フロー全体が止まり、攻撃者はリダイレクトURLとどのアプリユーザにも紐づいていない認可コードを取得する。
  3. 通常のCSRFの手口で被害者に取得したリダイレクトURLを実行させ、以降の認可フローを被害者に実行させることで、被害者のアプリと攻撃者のリソースを紐づける。

PKCE

弾く攻撃 攻撃による被害
被害者のリソースが、攻撃者のアプリに紐づく。 被害者の外部リソースにある情報が攻撃者に抜き取られる。

想定される攻撃シナリオ_ネイティブアプリ

  1. 認可コードリクエストのレスポンスで遷移するリダイレクトURLによって実行されるカスタムURLスキーム(紐づくネイティブアプリなどをブラウザ画面から実行できるリンク)と同じカスタムURLスキームを設定した攻撃用アプリを被害者のデバイスにインストールしておく。
  2. 実際にリダイレクトURLがブラウザで実行される時、本来ならば正規のアプリが実行されるが、同じカスタムURLスキームが設定された攻撃用アプリに認可コードが送られてしまう。
    --> リダイレクト先はリダイレクト前のセッションを保持するという脆弱さを突いた攻撃。
  3. 攻撃用アプリを通じて認可コードを横取りした攻撃者は、認可フローを乗っ取ることで被害者のアクセストークンを取得し、被害者のリソースに不正アクセスする。

想定される攻撃シナリオ_webアプリ

前提 : 認可コードを発行してからアクセストークンを取得するまでにラグがある、または認可コードを再利用してアクセストークンが発行できる場合。

  1. なんらかの方法で認可コードが奪われた場合、攻撃者は認可コードを添付したトークン取得リクエストを実行することでアクセストークンを取得する。

まとめ

CSRF対策は、攻撃者の認可コード(アクセストークン)と被害者のアプリユーザを紐付けさせないためのもの。
PKCEは、攻撃者のアプリユーザと被害者の認可コード(アクセストークン)を紐付けさせないためのもの。
PKCECSRF対策にもなると言っている人もいたりするが、それぞれが別の攻撃の対策になっているため、互いにとって変わることはできない。

Discussion