satoshi.inoue's blog

備忘録を兼ねているので、薄い内容の投稿もあります。

PKCE: OAuth2.0の認可コード横取り攻撃への対策

スポンサードリンク

これの続き。 www.acquapazzablog.com

認可コード横取り攻撃とは

Authorization Code Flowで認可コードを発行して、ブラウザから元のアプリにカスタムURLスキーム等で戻ってくるときに、攻撃者によってインストールされたプログラム等により、認可コードを抜き取られる攻撃です。

PKCEとは

OAuth 2.0 public clients utilizing the Authorization Code Grant are susceptible to the authorization code interception attack. This specification describes the attack as well as a technique to mitigate against the threat through the use of Proof Key for Code Exchange (PKCE, pronounced "pixy").

RFC 7636 - Proof Key for Code Exchange by OAuth Public Clients
Authorization Code Flowを使用するOAuth 2.0のPublic Clientは、認可コード横取り攻撃の影響を受けやすいので、コード交換のための証明鍵(PKCE、 "pixy"と発音)を使用して脅威を軽減します。

クライアント側でやること

code_verifier を生成する

The client first creates a code verifier, "code_verifier", for each OAuth 2.0 [RFC6749] Authorization Request, in the following manner:
code_verifier = high-entropy cryptographic random STRING using the unreserved characters [A-Z] / [a-z] / [0-9] / "-" / "." / "_" / "~" from Section 2.3 of [RFC3986], with a minimum length of 43 characters and a maximum length of 128 characters.

code_verifier = 予約されていない文字[A-Z] / [a-z] / [0-9] / " - " / "を使用した高エントロピー暗号化ランダムSTRING。 [RFC3986]のセクション2.3からの "/" _ "/"〜、最低長さ43文字、最大長さ128文字。  

code_challenge を生成する

The client then creates a code challenge derived from the code verifier by using one of the following transformations on the code verifier:

plain
      code_challenge = code_verifier
S256
      code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))

If the client is capable of using "S256", it MUST use "S256", as "S256" is Mandatory To Implement (MTI) on the server.
Clients are permitted to use "plain" only if they cannot support "S256" for some technical reason and know via out-of-band configuration that the server supports "plain".
The plain transformation is for compatibility with existing deployments and for constrained environments that can't use the S256 transformation.

簡単にまとめると、生成したcode_verifierからcode_challengecode_challenge_method(S256)で計算する。
S256は、SHA-256でハッシュし、base64urlでエンコードする。 ※ code_challenge_methodは、クライアントがS256を使用できる場合はこれを使用する必要があり、技術的な理由でS256をサポートできず、サーバーがplainをサポートしていることが分かっている場合に、クライアントはplainを使用できます。

Authorization Requestでパラメータを追加する

4.1.1. Authorization Requestに、code_challengecode_challenge_methodを含める。

Access Token Requestでパラメータを追加する

4.1.3. Access Token Requestに、code_verifierを含める。

サーバー側でやること

code_challengeとcode_challenge_methodを保存する

When the server issues the authorization code in the authorization response, it MUST associate the "code_challenge" and "code_challenge_method" values with the authorization code so it can be verified later.

4.1.1. Authorization Requestで認可コードを発行するときに、code_challengecode_challenge_methodの値を、認可コードに紐づけて保存しておく。

code_challengeを比較検証する

Upon receipt of the request at the token endpoint, the server verifies it by calculating the code challenge from the received "code_verifier" and comparing it with the previously associated "code_challenge", after first transforming it according to the "code_challenge_method" method specified by the client.
If the "code_challenge_method" from Section 4.3 was "S256", the received "code_verifier" is hashed by SHA-256, base64url-encoded, and then compared to the "code_challenge", i.e.:

BASE64URL-ENCODE(SHA256(ASCII(code_verifier))) == code_challenge

If the "code_challenge_method" from Section 4.3 was "plain", they are compared directly, i.e.:

code_verifier == code_challenge.

4.1.3. Access Token Requestでリクエストを受けると、サーバーは受け取ったcode_verifierからcode_challengeを計算し、認可コードに紐づけたcode_challengeと比較することによって検証します。

まとめ

PKCEは内容さえ理解してしまえば実装は難しくないので、プロバイダー側は是非実装しましょう。