リフレッシュトークンのローテーション: 開発者向けベストプラクティス
ユーザー満足度を維持しながらアプリのセキュリティを強化したいですか? リフレッシュ トークンのローテーションが役立ちます。リフレッシュ トークンは使用のたびに交換され、1 回限りの使用に有効であることが保証されます。これにより、セキュリティが向上し、リプレイ攻撃がブロックされ、セッション管理が簡素化されます。しかも、ユーザー エクスペリエンスを中断する必要はありません。
リフレッシュトークンローテーションを使用する理由
- より強力なセキュリティ: トークンの不正使用を制限し、明確なアクティビティ ログを提供します。
- より優れたコントロール: セッションを正確に管理し、必要に応じて即座にアクセスを取り消します。
- スムーズなユーザーエクスペリエンス: 頻繁にログインせずに長時間のセッションを行う。
仕組み:
- アクセス トークンの有効期限が切れると、更新トークンを使用して新しいトークンが要求されます。
- サーバーは、古いリフレッシュ トークンを無効にしながら、新しいアクセス トークンとリフレッシュ トークンを発行します。
- これにより、トークンの安全なチェーンが作成され、トークンの盗難などのリスクが軽減されます。
実装するための主な手順:
- アクセス トークンの有効期間を短く設定します (15 ~ 30 分)。
- 使い捨ての更新トークン(有効期間 7 ~ 14 日間)を使用します。
- トークンを安全に保存します (例: HTTP 専用の Cookie または安全なサーバー側ストレージ)。
- トークンの再利用や異常なログイン パターンなどの疑わしいアクティビティを監視します。
リフレッシュ トークンのローテーションを採用することで、ユーザーにとってシームレスな認証を維持しながら、アプリのセキュリティを強化できます。詳細を知りたいですか? 早速始めましょう!
ローテーションリフレッシュトークンを使用したセッションハイジャックの検出
リフレッシュトークンの仕組み
このセクションでは、OAuth 2.0 トークン プロセスと、更新トークンのローテーションによってセキュリティがどのように向上するかについて説明します。
OAuth 2.0 トークンフロー

OAuth 2.0 は、定義された一連の手順を通じてリフレッシュ トークンを管理します。ユーザーがログインすると、認可サーバーは、有効期間が短いアクセス トークン (15 ~ 60 分間有効) と有効期間が長いリフレッシュ トークン (7 ~ 14 日間有効) の 2 つのトークンを提供します。
プロセスの流れは次のとおりです。
1. 初期認証
ログインが成功すると、システムは次のメッセージを発行します。
- API 呼び出し用の短期アクセス トークン。
- 新しいアクセス トークンを要求するための、より長期の更新トークン。
2. アクセストークンの使用
クライアントは、次のように、各 API リクエストの Authorization ヘッダーにアクセス トークンを含めます。
承認: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... 3. トークンの更新
アクセス トークンの有効期限が切れると、クライアントはリフレッシュ トークンを使用して、ユーザーに再度ログインを要求することなく新しいトークンを要求します。
次に、トークンのローテーションがこのプロセスをどのように強化するかを見てみましょう。
トークンローテーションプロセス
トークンのローテーションは、リフレッシュのたびにトークンを置き換えてセキュリティを強化し、リフレッシュ トークンが 1 回のみ有効であることを保証します。仕組みは次のとおりです。
- クライアントはアクセス トークンの有効期限が切れていることに気付きます。
- 現在のリフレッシュ トークンをトークン エンドポイントに送信します。
- サーバーはリフレッシュ トークンを検証し、新しいアクセス トークンとリフレッシュ トークンを発行します。
- 古いリフレッシュ トークンは無効になります。
- サーバーは新しいトークンをクライアントに送り返します。
- クライアントは保存されているトークンを更新します。
この「1 回限りの使用」アプローチにより、トークンの安全なチェーンが作成され、悪用されるリスクが軽減されます。
使い捨ての更新トークンを適用するには、次のチェックを検討してください。
| チェック | 目的 | 実装 |
|---|---|---|
| トークン再利用検出 | リプレイ攻撃を防ぐ | 使用されたリフレッシュトークンをブラックリストで追跡する |
| 猶予期間 | ハンドル 競合状態 | 同時リクエストに30秒の猶予を与える |
| トークンファミリーの検証 | トークンの系譜を維持する | 新しいトークンに親トークンの参照を含める |
トークンのローテーションはバックグラウンドでシームレスに動作し、ユーザーエクスペリエンスをスムーズに保ちながらセキュリティを強化します。この方法を使用すると、ユーザーが頻繁にログインしなくても、安全で自動的な資格情報の更新が保証されます。
トークンローテーションの設定
基本的な設定手順
トークンのローテーションを設定するには、次のパラメータを使用して認証サーバーを構成します。
- アクセス トークンの有効期間を 15 ~ 30 分に設定します。
- 更新トークンの有効期間を最大 7 ~ 14 日間に制限します。
- セキュリティを確保するためにトークン検証チェックを有効にします。
- 不正使用を防ぐために、トークン エンドポイントにレート制限を適用します。
サーバーは、次の重要なフィールドを含むトークン レジストリを維持する必要があります。
| 分野 | 目的 | サンプル値 |
|---|---|---|
| トークンID | 一意の識別子 | uuid-v4 |
| 発行時間 | トークン作成のタイムスタンプ | 2025年3月18日午後2時30分(東部標準時) |
| 家族ID | グループ関連トークン | ファミリー-UUID-V4 |
| 前のトークン | 親トークンを追跡する | 前のトークンハッシュ |
| 失効ステータス | トークンのステータスを示す | 有効/取り消し |
設定が完了したら、コード内でトークンのローテーションを実装します。
プログラミング例
以下は Node.js を使用したトークンのローテーションの例です。
const jwt = require('jsonwebtoken'); const crypto = require('crypto'); async function rotateTokens(refreshToken) { const decodedToken = jwt.verify(refreshToken, process.env.SECRET_KEY); // 新しいトークン ペアを生成します const newAccessToken = jwt.sign( { userId: decodedToken.userId }, process.env.SECRET_KEY, { expiresIn: '30m' } ); const newRefreshToken = jwt.sign( { userId: decodedToken.userId, familyId: decodedToken.familyId, previousToken: crypto.createHash('sha256') .update(refreshToken).digest('hex') }, process.env.SECRET_KEY, { expiresIn: '7d' } ); // 古いリフレッシュトークンを無効にする await invalidateToken(refreshToken); return { accessToken: newAccessToken, refreshToken: newRefreshToken }; } トークンストレージのベストプラクティス
トークンのローテーションを実装した後は、次の手順に従ってトークンが安全に保存されるようにしてください。
- サーバー側ストレージ
トークンのメタデータを保存するには、Redis のような安全で高速なデータベースを使用します。Redis に組み込まれている有効期限サポートは特に役立ちます。await redis.setex( `token:${tokenId}`, 604800, // 7日間(秒単位)JSON.stringify(tokenMetadata) ); - クライアント側ストレージ
Web アプリケーションの場合、適切なセキュリティ フラグを使用して、HTTP のみの Cookie に更新トークンを保存します。res.cookie('refreshToken', token, { httpOnly: true, secure: true, sameSite: 'strict', maxAge: 604800000 // 7日間(ミリ秒) }); - モバイルアプリケーション
プラットフォーム固有の安全なストレージ オプションを使用します。- iOS: キーチェーンサービス
- Android: 暗号化された共有設定
- React Native: 暗号化された非同期ストレージ
トークンを保存するときは、次の間違いを避けてください。
- トークンを保管しないでください
ローカルストレージXSS 攻撃に対して脆弱であるためです。 - JWT ペイロードに機密データを埋め込まないようにしてください。
- 保存されているすべてのデータが暗号化されていることを確認します。
- リスクを軽減するために、アクセス トークンと更新トークンを別の保存場所に保管します。
sbb-itb-59e1987
セキュリティ対策
トークンの再利用の防止
リプレイ攻撃を阻止するには、トークンの状態の変化を追跡する集中システムを使用してトークンの使用状況を監視します。
const tokenRegistry = { async markTokenUsed(tokenId, timestamp) { const token = await db.tokens.findOne({ id: tokenId }); if (token.used || token.revoked) { throw new SecurityError('トークンの再利用が検出されました'); } await db.tokens.update({ id: tokenId, used: true, lastUsedAt: timestamp }); } }; トークンの再利用が検出された場合は、直ちに対処してください。
- トークンを取り消す さらなる悪用を防ぐためです。
- インシデントを記録する 監査目的のため。
- 再認証を強制する 影響を受けるセッションに対して。
- 管理者に通知する 違反行為を調査するため。
これらの手順は、以下に概説するトークン失効方法を補完するものです。
トークン失効手順
トークンの失効は、状況に応じてさまざまなレベルで適用できます。
| 失効タイプ | 使用する場合 | インパクト |
|---|---|---|
| 単一トークン | 1 台のデバイスで不審なアクティビティが発生 | 特定のトークンのみが影響を受ける |
| 家族の取り消し | 複数のデバイスが関与する侵害 | 関連するトークンはすべて無効になります |
| グローバル失効 | 重大なセキュリティインシデント | すべてのアクティブなトークンがシステム全体で取り消されます |
ファミリー トークンの失効の例を次に示します。
async function revokeTokenFamily(familyId) { await db.tokens.updateMany( { familyId: familyId }, { revoked: true, revokedAt: new Date(), reason: 'security_breach' } ); // クライアントに通知 await notifyClients(familyId); // セキュリティ イベントをログに記録 await logSecurityEvent({ type: 'family_revocation', familyId: familyId, timestamp: new Date() }); } 使用制限と追跡
トークン リクエストを監視することは、異常なアクティビティを見つけるために不可欠です。レート制限を使用し、使用パターンを追跡して潜在的な脅威を特定します。
const rateLimits = { tokenRequests: { window: '15m', maxAttempts: 100, blockDuration: '1h' }, refreshAttempts: { window: '24h', maxAttempts: 1000, blockDuration: '24h' } }; 監視すべき主な指標は次のとおりです。
- ユーザーごとのトークン更新頻度
- トークン更新の失敗
- リクエストの地理的起源
- 時間ベースの使用傾向
- 同時アクティブセッション数
次のような疑わしい動作に対してアラートを設定します。
- 異なる IP からの複数の更新試行
- 急速なトークンローテーション
- 通常以外の時間帯のアクセス
- 予期しない場所からのリクエスト
より優れた分析と脅威検出のために、トークンの使用状況データを時系列データベースに保存します。
const metrics = { async recordTokenUsage(tokenId, context) { await timeseriesDB.insert({ timestamp: new Date(), tokenId: tokenId, userId: context.userId, ipAddress: context.ip, userAgent: context.userAgent, geoLocation: await geolocate(context.ip) }); } }; 不正行為が検出された場合は、次の方法でセキュリティを強化します。
- 監視間隔の延長
- トークンの有効期限の短縮
- 追加の検証手順の追加
- より詳細な調査のために手動レビューを開始
テストとメンテナンス
テスト手順
トークンのローテーション プロセスが意図したとおりに機能することを確認するには、自動テストが不可欠です。この機能をテストする方法の例を次に示します。
describe('トークン ローテーション テスト', () => { test('トークンをローテーションして検証する必要があります', async () => { // 基本的なローテーションをテストします const initialToken = await generateRefreshToken(); const rotatedToken = await rotateToken(initialToken); expect(rotatedToken).not.toEqual(initialToken); expect(await validToken(rotatedToken)).toBeTruthy(); // 完全な認証フローをテストします const authResponse = await authenticate(credentials); await simulateTokenExpiry(authResponse.accessToken); const newTokens = await performTokenRotation(authResponse.refreshToken); await verifyTokenLineage(authResponse.refreshToken, newTokens.refreshToken); }); }); トークンのローテーションが期待どおりに機能することを確認したら、システムのパフォーマンスを監視して、問題を早期に特定して解決します。
システム監視
信頼性を維持するために、主要な指標を使用してトークンローテーションのパフォーマンスを追跡します。
| メトリック | 説明 | アラートしきい値 |
|---|---|---|
| 回転遅延 | 回転完了までの時間 | > 500ミリ秒 |
| 成功率 | 成功したローテーション | < 99.9% |
| トークンチェーンの長さ | 順番に回転する | > 50回転 |
| エラー頻度 | 1時間あたりの失敗回数 | > 10 エラー |
さらに、追跡可能性を高めるために、すべてのトークンライフサイクルイベントをログに記録します。
const rotationLogger = { async logRotationEvent(event) { await logger.info('token_rotation', { timestamp: new Date().toISOString(), tokenId: event.tokenId, rotationDuration: event.duration, status: event.status, errorCode: event.error || null }); } }; エラー管理
徹底したテストと監視を行っても、エラーが発生する場合があります。エラーに効果的に対処するために、専用の回復メカニズムを使用してください。
const errorHandler = { async handleRotationError(error, context) { // 統合回路ブレーカーによるプライマリ エラー処理 if (this.failureCount >= 5) { await this.activateFailover(); return; } switch(error.code) { case 'TOKEN_EXPIRED': await forceReauthentication(context.userId); break; case 'DATABASE_ERROR': await this.retryWithBackoff(context); break; default: await this.notifyAdministrator(error); } await metrics.recordError(error); }, async retryWithBackoff(context, attempts = 0) { if (attempts > 3) return; await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempts) * 1000)); return this.handleRotationError(context, attempts + 1); } }; このアプローチにより、エラーが効率的に管理され、システムの中断が最小限に抑えられます。
結論
重要なポイント
リフレッシュトークンのローテーションにより、 安全, パフォーマンス、 そして ユーザーエクスペリエンス心に留めておくべき基本的なプラクティスは次のとおりです。
- システムパフォーマンスを最適化する 継続的な監視を通じて。
- 回復力のあるエラー処理を実装する 問題からのスムーズな回復を可能にします。
- 厳格なテストを実施する 回転メカニズムを検証し、微調整します。
実装のためのステップバイステップガイド
トークンのローテーションを実装する準備ができたら、プロセスの詳細は次のとおりです。
- 初期設定
まず、業界標準の暗号化方式を使用して安全なトークン ストレージを構築します。レート制限を組み込み、認証サーバーが需要に合わせて拡張できるようにします。 - セキュリティ構成
トークンの有効期間、ローテーション ウィンドウ、制限などの重要なパラメータを定義します。たとえば、簡単な構成は次のとおりです。const securityConfig = { tokenLifetime: 3600, // トークンの有効期間は 1 時間です rotationWindow: 86400, // リフレッシュ トークンの有効期間は 24 時間です maxRotations: 30, // トークンのローテーションの最大回数 jwtAlgorithm: 'RS256', // 非対称暗号化アルゴリズム tokenLength: 256 // トークンのサイズ (ビット単位) }; - 監視設定
システム パフォーマンスのしきい値を確立し、異常に対するアラートを設定します。指標が需要の増加を示したら、インフラストラクチャを拡張できるように準備します。 - 実稼働環境への導入
重要な指標に注意しながら、システムを徐々に展開します。監査とトラブルシューティングのために、ローテーションイベントの詳細なログを維持します。スケーラブルで信頼性の高いインフラストラクチャを実現するには、次のようなホスティングソリューションを検討してください。 Serverion (https://server.com) は、高性能な環境をサポートします。