PKCE とは:基本概念から深い理解へ
この記事は、悪意のあるアプリケーションが認可コードを傍受するのを防ぐことで、PKCE(Proof Key for Code Exchange)が OAuth 2.0 認可コードフローをどのように保護するかを説明し、基本概念から包括的な理解へと導きます。
Proof Key for Code Exchange(PKCE)は認可コードフローの拡張機能であり、もともとはモバイルアプリの認可コードフローを保護するために設計され、現在ではシングルページアプリでも使用することが推奨されています。OAuth 2.1から、PKCEは公開クライアントおよび機密(プライベート)クライアントを含むすべてのタイプのクライアントに対して適用されます。
この記事では、PKCEがなぜ作られ、どのようにアプリケーションを保護するのかについての深い理解を提供します。
なぜ PKCE が必要なのか?
OAuth 2.0 認可コードフローでは、ユーザーがアプリケーションを通じてサインインを要求します。認証サーバーはユーザーを認証ページに誘導します。ユーザー認証後、サーバーはアプリケーションに認可コードを返し、その後、アプリケーションはこのコードを使用して認証サーバーからアクセストークンを要求します。
このフローには大きなセキュリティリスクがあります:認可コードは悪意のあるプログラムによって傍受される可能性があります。これは特に、他のアプリケーションが同じリダイレクト URI を登録し、認可コードを傍受する可能性があるモバイルデバイスで懸念されます。
次の図に示すように、傍受プロセスは以下のとおりです:
ステップ (1):アプリは、傍受されない安全な API を介して認可要求を行います。このステップで、リクエストにはリダイレクト URI も提供されます。
ステップ (2):リクエストは、OAuth 2.0 認可サーバーに転送されます。OAuth では、TLS の使用が必要なため、この通信は TLS によって保護され、傍受されることはありません。
ステップ (3):認可サーバーは認可コードを返します。
ステップ (4.a):認可コードは、ステップ (1) で提供されたリダイレクト URI を介してリクエストした者に返されます。このステップで、悪意のあるアプリがリダイレクト URI のハンドラーとして自身を登録している場合、認可コードを傍受できます。この認可コードを使用して、攻撃者はそれぞれステップ (5.a) および (6.a) でアクセストークンを要求し取得できます。
上記のように、OAuth 2.0 認可コードフローにおいて、認可コードが傍受されると、攻撃者はそれを利用してアクセストークンを取得できるため、認可コードの傍受を防ぐメカニズムが必要であり、それが PKCE の作成につながりました。
PKCE はどのように機能するのか?
前述のように、攻撃を防ぐには、リクエストを発行したアプリだけがアクセストークンを要求し取得できるようにする必要があります。ここで PKCE の出番です。
PKCE は、「証明キー」コンセプトを導入することによって、この問題を解決します。
認可コードを要求するとき、アプリケーションは最初にランダムなコード検証子を生成し、それをローカルに保存します。次に、特定のアルゴリズムを用いてこのコード検証子をコードチャレンジに変換します。アプリケーションは、認可コード要求時にコードチャレンジとコードチャレンジメソッドの両方を認証サーバーに送信します。
コード検証子はランダムに生成された文字列であり、コードチャレンジは変換を通じてコード検証子から導かれます。サポートされる変換方法は次のとおりです:
plain
:コード検証子をそのままコードチャレンジとして使用
S256
:コード検証子に SHA-256 ハッシュを適用し、さらに Base64URL エンコードを行います。ハッシュ出力からコード検証子に戻すことはできず、plain
メソッドは伝送中に中間者攻撃に脆弱である可能性があるため、セキュリティの観点からS256
を使用することが強く推奨されます。
ユーザー認証後、認証サーバーはアプリケーションに認可コードを返します。アクセストークンを要求する際、アプリケーションは認可コードとコード検証子の両方を認証サーバーに送信します。サーバーは、以前に受け取った「コードチャレンジメソッド」を使用して「コード検証子」を変換し、得られた結果を以前に受け取った「コードチャレンジ」と比較し、「コード検証子」の所持をクライアントに対して検証します。
ステップ (1-3):アプリは「コード検証子」という秘密を生成し記録し、「コードチャレンジ」という変換バージョンを導き、「コードチャレンジメソッド」という変換方法と共に OAuth 2.0 認可要求で送信します。
ステップ (3-6):Auth Server は通常通りに応答しますが、「コードチャレンジ」と「コードチャレンジメソッド」を記録します。
ステップ (7.a):アプリは通常通り、ステップ (1) で生成された「コード検証子」秘密を含めてトークンエンドポイントに認可コードを送信します。
ステップ (8.a-9.a):認可サーバーは「コード検証子」を「コードチャレンジ」に変換し、ステップ (1-3) から「コードチャレンジ」と比較します。等しくない場合はアクセスが拒否されます。
この場合、悪意のあるアプリがステップ (6.b) で認可コードを傍受しても、「コード_verifier」秘密を所持していないため、アクセストークンを取得することはできません。「コード検証子」は TLS を介して送信されるため、傍受することはできません。
まとめ
この記事では、PKCE がどのように機能し、認可コードフローを保護するために必要である理由を説明しました。「証明キー」メカニズムを追加することで、PKCE は悪意のあるアプリケーションが認可コードを傍受して悪用するのを防ぎます。この説明があなたの PKCE の理解を深めることを願っています。