こんにちは。セキュリティの現場で長年、泥臭いインシデントと向き合ってきた筆者です。
今日は、OAuth 2.0の「リフレッシュトークン」という、一見便利だけど扱いを間違えると非常に恐ろしい仕組みについてお話しします。難しそうな用語が並びますが、大丈夫。まずは身近な例から紐解いていきましょう。
—
1. なぜ「リフレッシュトークン」が必要なの?
あなたが高級マンションに住んでいると想像してください。マンションに入るには「電子キー(アクセストークン)」が必要です。でも、この電子キーはセキュリティのために「1時間で有効期限が切れる」設定になっています。
これだと、1時間ごとにわざわざ管理室まで行って新しい鍵をもらう必要がありますよね。それは面倒すぎます。そこで登場するのが「リフレッシュトークン」です。
これは「1時間経ったら、この特別なカード(リフレッシュトークン)を見せれば、新しい電子キーを再発行してあげるよ」という「鍵の引換券」のようなものです。この引換券さえあれば、あなたは管理室に行かなくても、スマホで新しい電子キーを自動で手に入れられます。
2. 泥棒が狙う「引き換えの瞬間」
ここで問題が発生します。もし、誰かがあなたのカバンから「引換券(リフレッシュトークン)」を盗み出したらどうなるでしょうか?
泥棒はその引換券を使って、あなたの代わりに管理室で新しい電子キーを発行し放題になります。しかも、あなたが「あれ? 鍵が効かないぞ?」と気づいたときには、泥棒はすでに新しい鍵を使ってあなたの部屋に侵入しているかもしれません。
これが、セキュリティの世界で最も恐れられている「トークンの盗難」です。
3. 「リフレッシュトークン・ローテーション」という最強の防犯対策
このリスクを最小限にする仕組みが「リフレッシュトークン・ローテーション(再利用検知)」です。
先ほどのマンションの例で言うと、「引換券を使うたびに、古い券は無効になり、新しい券が発行される」というルールにするのです。
- あなたが引換券を使うと、新しい電子キーと「新しい引換券」をもらいます。
- この瞬間、古い引換券はゴミ同然(無効)になります。
もし泥棒が古い引換券を持っていても、それはもう使えません。さらに、もし「使ったはずの引換券」が再び使われたら、システム側は「おっと、これは誰かが不正に複製したな!」と気づくことができます。この時、そのユーザーに関連する全てのリフレッシュトークンを即座に強制無効化して、被害を食い止めるのです。
4. 実装のイメージ(開発者の方へ)
実際にシステムを組む際、サーバーサイドではどのような動きになるのか、擬似コードで見てみましょう。
// リフレッシュトークン要求を受け取った時の処理ロジック
async function handleRefreshToken(oldRefreshToken) {
// 1. データベースから該当トークンの情報を取得
const tokenRecord = await db.findToken(oldRefreshToken);
// 2. もしトークンが見当たらない(あるいは既に使用済みフラグがある場合)
if (!tokenRecord || tokenRecord.isUsed) {
// 泥棒が「古い引換券」を盗んで使おうとした可能性が高い!
// 関連する全てのトークンを即座に破棄して、アカウントを守る
await db.revokeAllTokensForUser(tokenRecord.userId);
throw new Error(“セキュリティ違反:不正なトークンが検出されました。再ログインしてください。”);
}
// 3. ローテーションの実行:古いトークンを無効化し、新しいものを発行
await db.markAsUsed(oldRefreshToken);
const newAccessToken = generateAccessToken();
const newRefreshToken = generateRefreshToken();
await db.saveNewToken(newRefreshToken, tokenRecord.userId);
return { newAccessToken, newRefreshToken };
}
実装時のポイント
- 即時無効化: トークンが一度使われたら、即座に「使用済み」フラグを立てるか、DBから削除してください。
- 猶予期間(Grace Period): ネットワークの瞬断でリクエストが再送されるケースも考慮し、数秒間だけ古いトークンを有効にする実装もありますが、まずは「厳密な1対1の置き換え」から始めるのが鉄則です。
- ログの記録: 「誰が」「いつ」不正なトークンを使用しようとしたか、IPアドレスを含めて必ずログに残しましょう。
5. 最後に:セキュリティは「完璧」を目指さない
正直に言うと、リフレッシュトークンをローテーションしても、攻撃者があなたのPCを物理的に乗っ取っていれば防ぎようがありません。セキュリティ対策に「絶対」はありません。
しかし、このような「泥棒にバレたとしても、被害を最小限に留める」という考え方は、現代の安全なアプリケーション開発において最も重要な「多層防御」の考え方です。
難しく考えすぎず、まずは「引換券(リフレッシュトークン)は使い捨てにする」という意識から始めてみてください。これだけで、あなたのサービスを守る強固な盾になりますよ。
一歩ずつ、安全な開発の道を進んでいきましょう!応援しています。

コメント