OAuth 2.0 における通信は基本的に TLS で守られるのが基本なのだけれど、ひとつ TLS で守られない通信があります。それは Client・User-Agent 間の通信です。 Authorization Code Grant においては、認可サーバから認可コードを受けた User-Agent がその情報をクライアントに渡すときに発生します。
Authlete さんの以下の図がすごくわかりやすいのですが、User-Agent (Operation System Browser) から Malicious App に認可コードが漏れていることがわかります。 Native App では、これは Custom Scheme が悪意のある App に上書きされた場合等で発生します。 もちろん、認可コードが漏れたら、アクセストークンも漏れるので、このような認可コードの漏洩は防がなければなりません。
PKCE
これを防ぐのが、RFC 7636 で定義されている Proof Key for Code Exchange by OAuth Public Clients、通称 PKCE (ピクシー) です。 PKCE の原理はすごくシンプルで、認可サーバ側で、「認可リクエスト」を送信してきたクライアントと「トークンリクエスト」を送信してきたクライアントが同一であることを確認するという方法です。
- クライアントは、認可リクエストを送信する際、
code_verifier
という乱数を発生させた上で、ハッシュ関数t
を用いたハッシュ値を計算します。結果としてのハッシュ値t(code_verifier)
とハッシュ関数を、それぞれcode_challenge
、code_challenge_method
として認可リクエストに含め、認可サーバに送信します。 - 認可サーバは、認可リクエストを受信した際、
code_challenge
、code_challenge_method
を保存しておきます。 - クライアントは、トークンリクエストを認可サーバに送信する際、1. で生成した
code_verifier
をトークンリクエストに含めます。 - 認可サーバは、トークンリクエストを受信すると、2. で保存した
code_challenge_method
であるt
と使ってt(code_challenge)
を計算し、それが、code_challenge
と一致するかを検証します。
パラメータ追加のみで、認可フローを変えなくて良いので、導入しやすい方法だと思います。
上記ではハッシュ関数としていますが、実際に PKCE で使用できるのは以下の 2 つですが、まぁ S256 一択ですかね。
plain
: 恒等関数S256
: SHA-256 でハッシュ化した値を BASE64 に変換したもの