「その認可コード、盗まれてない?」――初心者でもわかるOAuth 2.0 PKCEの重要性
こんにちは。セキュリティの世界へようこそ。
日々、何千もの脆弱性と向き合っていると、「理論は完璧なのに、なぜかそこだけ穴が開いている」という現場に何度も遭遇します。
今日は、OAuth 2.0における「PKCE(ピクシー)」という仕組みについてお話しします。名前は可愛らしいですが、実はこれ、スマホアプリやシングルページアプリケーション(SPA)を守るための、極めて「硬派で重要な鍵」なんです。
小難しい専門用語は一旦脇に置いて、まずは身近な「家の鍵」の話から始めましょう。
—
1. 認可コードの受け渡しは「窓から鍵を投げる」ようなもの?
OAuth 2.0の仕組みでは、ユーザーがログインした後に、サーバーから「認可コード」というチケットが発行されます。アプリはこのチケットをサーバーに見せることで、「私は本人ですよ」と証明し、アクセストークン(いわば家のマスターキー)を受け取ります。
でも、考えてみてください。スマホアプリからログインする際、この「認可コード」が、ブラウザを経由してアプリに渡されるとき……悪意ある別のアプリがそのコードを横取りできてしまったら?
いわば、「玄関のドアを閉める前に、窓の外から通行人に鍵を投げ渡している」ような状態です。もし泥棒がその場で鍵をキャッチしたら、家の中に簡単に入れてしまいますよね。これが「認可コード横取り攻撃」の正体です。
—
2. PKCE(ピクシー)という「秘密の合い言葉」
このリスクを防ぐために登場したのが、PKCE(Proof Key for Code Exchange)です。
PKCEの考え方はとてもシンプルです。
「鍵を投げる前に、自分だけが知っている『秘密の合い言葉』をあらかじめ登録しておく」というものです。
仕組みの3ステップ
1. 準備: アプリは最初に「ランダムな文字列(code_verifier)」を作り、それを加工した「暗号のような文字列(code_challenge)」を用意します。
2. 申請: ログイン時に「この『暗号(challenge)』とセットになる鍵をあとで持ってくるから、ログインさせて!」とサーバーに伝えます。
3. 検証: 認可コードを交換する際、アプリは「最初に決めた『合い言葉(verifier)』はこれだ!」とサーバーに突きつけます。サーバーは、最初に渡された暗号と照らし合わせ、「なるほど、確かに本物のアプリだ!」と納得して初めてマスターキーを渡します。
もし泥棒が認可コードだけを盗んだとしても、「秘密の合い言葉(verifier)」は盗んでいないので、サーバーを騙すことはできません。
—
3. 実装のステップ:コードで見てみよう
難しく考えず、まずは概念的な流れをコードでイメージしてみましょう。
// 1. まずはランダムな文字列(code_verifier)を生成
const codeVerifier = generateRandomString(64);
// 2. それをハッシュ化して(code_challenge)を作る
// サーバーにはこのchallengeだけを先に送っておく
const codeChallenge = base64URLEncode(sha256(codeVerifier));
// — (ここでログイン処理が行われ、認可コードを取得する) —
// 3. 認可コード交換時に、最初に作ったverifierを添えて送る
const requestBody = {
grant_type: ‘authorization_code’,
code: ‘盗まれるかもしれない認可コード’,
client_id: ‘your-app-id’,
code_verifier: codeVerifier // 「私、これを作った本人ですよ!」という証拠
};
サーバー側では、受け取った code_verifier を同じように加工し、最初に登録された code_challenge と一致するかをチェックします。この計算が一致しない限り、アクセストークンは絶対に発行されません。
—
4. なぜこれが「最強の防犯」なのか
PKCEの素晴らしいところは、「通信経路が盗聴されていても、鍵そのものは盗まれない」という点です。
かつては「通信を暗号化すれば大丈夫」と言われていましたが、スマホ内の別の悪意あるアプリが「カスタムURLスキーム(特定のアプリを呼び出す仕組み)」を悪用して、ブラウザからアプリに渡されるはずの情報を横取りする手法が現実のものとなりました。
PKCEは、その「途中の経路がどうなっていようが、最終的な本人確認の整合性で守る」という、非常に堅牢な設計になっています。
—
最後に:一歩ずつ対策を学んでいきましょう!
セキュリティ対策というと、「完璧にしなければいけない」とプレッシャーを感じるかもしれません。でも、まずは「この認可コードは盗まれるかもしれない」という前提に立つことが、最初の一歩です。
今開発しているアプリで、まだPKCEが有効になっていないのであれば、ぜひ今日から導入を検討してください。最近の認証ライブラリ(Auth0, Firebase Auth, MSALなど)を使っていれば、設定をオンにするだけでPKCEが動くようになっていることも多いですよ。
「鍵を投げ渡す」のではなく、「本人確認の合い言葉」を使う。
この小さな工夫が、あなたのサービスとユーザーの信頼を守る大きな防壁になります。
もし実装で悩んだり、「自分の環境だとどうなるの?」という疑問があれば、いつでも聞いてくださいね。一緒に安全なコードを書いていきましょう!
コメント