invalid_grant
security
auth_error
ai_generated
true
OAuth2 刷新令牌重放检测:相同的刷新令牌被多次使用
OAuth2 refresh token replay detected: same refresh token used more than once
ID: security/oauth2-token-replay-via-refresh-token
80%修复率
85%置信度
1证据数
2023-05-15首次发现
版本兼容性
| 版本 | 状态 | 引入 | 弃用 | 备注 |
|---|---|---|---|---|
| OAuth 2.0 RFC 6749 | active | — | — | — |
| Spring Security OAuth2 2.5.x | active | — | — | — |
| Keycloak 21.0.x | active | — | — | — |
| Auth0 Node.js SDK 2.0.0 | active | — | — | — |
| Okta .NET SDK 3.0.0 | active | — | — | — |
根因分析
OAuth2 刷新令牌在每次使用后未轮换,导致窃取令牌的攻击者可以无限重放以获取新的访问令牌。
English
OAuth2 refresh token is not rotated after each use, allowing an attacker who steals the token to reuse it indefinitely and obtain new access tokens.
官方文档
https://datatracker.ietf.org/doc/html/rfc6749#section-1.5解决方案
-
Implement refresh token rotation: issue a new refresh token with each access token refresh and invalidate the old one. Example: In Spring Security OAuth2, set `refreshTokenRotationEnabled=true` in authorization server config.
-
Use refresh token expiration with a short TTL (e.g., 15 minutes) combined with rotation, and require re-authentication after expiry.
-
Add a client-side nonce or binding to refresh token to tie it to a specific device or session, preventing cross-device replay.
无效尝试
常见但无效的做法:
-
95% 失败
Longer expiration gives attackers more time to exploit stolen tokens; does not address the fundamental replay vulnerability.
-
70% 失败
Blacklists are hard to maintain in distributed systems and require real-time synchronization; attackers can still replay before blacklisting.
-
85% 失败
Rate limiting may block legitimate users and does not prevent a single replay attack; attacker can still use the token once before rate limit kicks in.