PKCEは特にスマホアプリやブラウザアプリでOAuth 2.0を使うとき、OAuth 2.0の安全性を支えるのに不可欠な存在。
PKCE(ピーケーシーイー)
読み方はピーケーシーイー。
PKCE (Proof Key for Code Exchange) 。
PKCEは何なの?
PKCEは、RFC 7636で定義された「仕様(規格・プロトコル)」です。
PKCEは、特定のソースコードやツールではなく、認可サーバーとクライアントアプリが従うべき手順を定めたルールです。
規格です。文書です。概念。
認可コードの盗聴を防ぎ、スマホアプリなどのセキュリティを強化するために作られたOAuth 2.0の拡張規格。
いつ誰が作ったの?
OAuthやOpenID Connectのセキュリティ仕様の標準化を主導した、インターネットセキュリティの専門家パトリック・マクディー(Patrick MacDona)氏が中心となり、2015年9月に2015年9月にIETF(Internet Engineering Task Force)によって正式な規格として承認され、RFC 7636として公表されました。
パトリック・マクディー氏は何者?
OAuthとOpenID Connectの標準化を主導した、インターネットセキュリティの専門家。
マクディー氏は、IETFなどの標準化団体での活動を通じて、OAuth 2.0やOpenID Connectなど、ID連携と認可に関する重要な仕様の策定に深く関わってきました。
なぜPKCEをみんなが採用しているの?
セキュリティ上の重大なリスクを解決し、大規模なテック企業が「必須」として実装したから。
PKCEが広く採用されている理由は
- セキュリティ上の必要性: スマホアプリなどのパブリッククライアントが持つ認可コード盗聴という深刻な脆弱性を、確実に解決した
- 業界の推進力: Google、Microsoft、Amazonなどの主要プラットフォームが、自社のOAuth実装においてPKCEを必須要件として採用した
これにより、「このやり方が正しい」という合意が形成され、PKCEはデファクトスタンダード(事実上の標準)となった。
誰が提供者で誰が利用者?
PKCEを”使う”のは「巷のアプリ開発者」、PKCEを”提供する(検証する)”のは「大きなサービス提供者」。
OAuth提供者がPKCEの検証ロジックを提供し、OAuthを使用したい巷のアプリがPKCEの証明ロジックを使う。
| 登場人物 | 名称(OAuth用語) | 役割とPKCEでの動作 | 誰が実装し、誰が提供するか |
| 1. サービス提供者 | 認可サーバー (Authorization Server) | PKCEの検証ロジックを提供する側です。code_challengeを受け取り保存し、トークン交換時にcode_verifierを受け取って照合する処理を実装します。 | Google, X (Twitter), Facebookなど、ID連携サービスを提供する企業が実装・提供します。 |
| 2. 外部アプリ開発者 | クライアント (Client) | PKCEの証明ロジックを使う側です。code_verifierを生成・保持し、code_challengeを計算してリクエストに含める処理を実装します。 | あなたの開発するスマホアプリやウェブサービスの開発者が実装します。 |
| 3. 最終利用者 | リソースオーナー (Resource Owner) | PKCEの仕組みを意識せずに利用する側です。アプリの連携時に「許可する」ボタンを押す役割を担います。 | 連携サービスにログインし、アプリを利用する一般ユーザーです。 |
PKCEは具体的にどう盗聴を防ぐの?
フローごとに「使い捨ての秘密の証明書」を導入し、盗聴されたコードの無効化を実現します。
PKCEは、クライアントシークレットの代わりに、フローごとに一度だけ使用する「ワンタイムの秘密鍵」のような仕組みを使います。
巷の開発者は何をどう使うの?
通常の認可コードフローに2つの新しいパラメータを追加します。
1. トークン交換の前にクライアントアプリが行う準備
クライアントアプリ(あなたのアプリ)は、認可リクエストを開始する前に、以下の準備をします。
| 項目 | 値の生成と役割 |
code_verifier | ランダムな秘密の文字列。 フローごとに一度だけ生成されます(使い捨ての秘密鍵)。この値はアプリ内に秘密に保持されます。 |
code_challenge | code_verifierをSHA256でハッシュ化し、Base64 URLエンコードしたもの。この値をサーバーに提示します。 |
2. 認可リクエスト時(サーバーへのチャレンジ提示)
ユーザーを認可サーバー(Googleなど)へ誘導する際、以下のパラメータを追加します。
| パラメータ | 値 | 役割 |
code_challenge | ステップ1で生成したハッシュ値 | サーバーに「後でこの秘密を証明するよ」と予告する |
code_challenge_method | S256 | ハッシュ化にSHA256を使ったことをサーバーに伝える |
サーバーの反応: サーバーはこのcode_challengeを認可コードと紐付けて保存し、ユーザー承認後に認可コードを返します。
3. トークン交換時(秘密の証明)
クライアントアプリが、認可コードと引き換えにアクセストークンを要求する際、以下のパラメータを追加します。
| パラメータ | 値 | 役割 |
code_verifier | ステップ1で生成した秘密の生の文字列 | トークンを要求しているのが本物のアプリであることを証明する |
サーバーは、受信したcode_verifierを自分でハッシュ化(S256)し、最初に保存していたcode_challengeと一致するか検証します。
この検証が成功した場合のみ、アクセストークンが発行されます。これにより、認可コードが盗聴されても、code_verifierを知らない攻撃者はトークンを取得できません。
まとめると
PKCEを使うとは、OAuthフローの開始時にランダムな秘密を作り、ハッシュ値(チャレンジ)をサーバーに送り、トークン交換時に秘密の元となる文字列(verifier)を提出して認証するということです。
ソースコードとしては何がどうなってるの?
HTTPリクエストとサーバー側の検証ロジックとして実装されます。
PKCEはなぜ必要になった?
クライアントシークレット(アプリの秘密鍵)を安全に隠せない「パブリッククライアント」(例:ネイティブアプリ、SPA)を守る目的で導入。
OAuthの認可コードの盗聴と、Client Secretの漏洩という2つの弱点を補い、OAuthの認可コードフローの安全性が飛躍的に向上しました。
PKCE登場前はどんな問題があった?
Client Secretは「秘密」を保てない
スマホアプリなどのパブリッククライアントは、Client Secret(秘密鍵)をアプリの実行ファイルやブラウザのソースコード内に埋め込む必要があります。その結果、攻撃者によって容易に解析され、抜き取られてしまいます。
このため、パブリッククライアントは、Client Secretを使ってトークン交換時の「本人証明」を行うことができません。
認可コード盗聴を防ぐ手段がない
パブリッククライアントは、以下の問題が起こります。
- 攻撃者が通信を盗聴し、URL経由で渡される認可コードを不正に盗み取ります。
- 認可サーバーは、盗聴された認可コードを使ってトークンを要求してきたのが本物のアプリなのか、それとも不正な攻撃者なのかを判断するための秘密の照合手段がありません。
- その結果、盗聴された認可コードを使ってアクセストークンが不正に取得されてしまうという問題がありました。
PKCEは、この「秘密鍵がないため、認可コードの不正利用を防げない」という問題に対し、フローごとに変化する「一時的な秘密の証明(code_verifier)」を導入することで、抜本的な解決策を提供した。
攻撃者が認可コードを盗んだらどうなる?
code_verifier(秘密の文字列)を知らないため、トークン交換がサーバーに拒否され、攻撃は失敗する。
攻撃者が認可コードだけを盗んでも、トークン交換の際にcode_verifierを提出しなければ、サーバーは照合(検証)ができないため、アクセストークンは発行されません。
「PKCEをサポートしている」とはどういう意味?
サービスがRFCの挙動通りに、検証ロジックを正しく実装している状態を意味する。
サービス(認可サーバー)が以下のセキュリティ検証を正しく行っていることを意味します。
例えば、GoogleはPKCEをサポートしている。
サポートしているかどうかは、ソースコードを読んだりするよりも、外部から見える挙動がRFCの通りになっているか?で判断される。
コメント