OAuth PKCE
本文约需 2 分钟阅读
PKCE (Proof Key for Code Exchange、「ピクシー」と発音) は、OAuth 2.0 の認可コードフローに 追加されたセキュリティ拡張です。RFC 7636 として 2015 年に標準化されました。 もともとモバイルアプリのように client_secret を安全に保持できない パブリッククライアント向けに設計されましたが、その有効性から OAuth 2.1 ではすべてのクライアントタイプで必須化される方向で進んでいます。
認可コードインターセプト攻撃とは
PKCE が解決する脅威を理解するには、まず攻撃の仕組みを知る必要があります。 OAuth 2.0 の認可コードフローでは、ユーザーが認可サーバーでログインした後、 認可コードがリダイレクト URI 経由でクライアントに返されます。 モバイル OS ではカスタム URL スキーム (例: myapp://) を使ってリダイレクトしますが、 悪意のあるアプリが同じ URL スキームを登録していると、認可コードを横取りできてしまいます。
SPA (Single Page Application) でも同様のリスクがあります。ブラウザの履歴やリファラーヘッダー、ブラウザ拡張機能を 通じて認可コードが漏洩する可能性があるためです。
code_verifier と code_challenge の仕組み
PKCE は「認可リクエストを送った本人だけがトークンを取得できる」ことを暗号的に保証します。 仕組みはシンプルで、2 つの値を使います。
| 要素 | 生成タイミング | 役割 |
|---|---|---|
| code_verifier | 認可リクエスト前にクライアントが生成 | 43-128 文字のランダム文字列。クライアントだけが保持する秘密 |
| code_challenge | code_verifier から算出 | SHA-256 ハッシュの Base64URL エンコード。認可リクエストに含める |
攻撃者が認可コードを横取りしても、code_verifier を持っていなければトークンを取得できません。 code_challenge からは code_verifier を逆算できない (SHA-256 の一方向性) ため、 認可リクエストを傍受しても無意味です。
パブリッククライアントでの必要性
従来の OAuth 2.0 では、コンフィデンシャルクライアント (サーバーサイドアプリ) は client_secret でトークンエンドポイントを保護できました。しかし SPA やモバイルアプリは ソースコードがユーザーの手元にあるため、client_secret を安全に埋め込めません。 PKCE はこの問題を解決し、client_secret なしでも認可コードの正当な所有者を証明できます。
CSRF 対策としても PKCE は有効です。 state パラメータと異なり、PKCE は暗号的な検証を行うため、より堅牢な保護を提供します。セッショントークンの 管理と組み合わせることで、認証フロー全体のセキュリティが向上します。
OAuth 2.1 での必須化
OAuth 2.1 (ドラフト段階、2025 年時点) では、PKCE がすべてのクライアントタイプで 必須になります。コンフィデンシャルクライアントであっても PKCE を使用しなければなりません。 これは「defense in depth (多層防御)」の考え方に基づいています。 client_secret が漏洩した場合でも、PKCE があれば認可コードの横取りを防げるためです。OpenID Connect を利用している場合も、 PKCE の併用が強く推奨されています。
よくある実装ミス
- code_challenge_method に plain を使用する。plain は code_verifier をそのまま code_challenge として送るため、傍受されると意味がない。必ず S256 (SHA-256) を使用すること
- code_verifier をセッションストレージではなくローカルストレージに保存する。 XSS 攻撃で読み取られるリスクが高まる
- code_verifier のエントロピーが不足している。暗号的に安全な乱数生成器 (Web Crypto API の getRandomValues) を使用すること
OAuth 権限の落とし穴やAPI キー管理の記事も あわせて確認すると、認可フロー全体のセキュリティ設計が見えてきます。API キーとの使い分けも 実務では重要な判断ポイントです。OAuth セキュリティの関連書籍 (Amazon)で体系的に学ぶのもおすすめです。
这篇文章对您有帮助吗?