缺少PKCE导致的OAuth2授权码注入
OAuth2 authorization code injection via missing PKCE
ID: security/oauth2-authorization-code-injection-via-missing-pkce
版本兼容性
| 版本 | 状态 | 引入 | 弃用 | 备注 |
|---|---|---|---|---|
| OAuth2.0 | active | — | — | — |
| Spring Security 5.7+ | active | — | — | — |
| Okta 2023.04.0 | active | — | — | — |
| Auth0 2023.01 | active | — | — | — |
根因分析
没有使用PKCE(代码交换证明密钥)的OAuth2授权码流程允许攻击者拦截授权码并交换令牌,绕过预期的客户端。
English
OAuth2 authorization code flow without PKCE (Proof Key for Code Exchange) allows an attacker to intercept the authorization code and exchange it for tokens, bypassing the intended client.
官方文档
https://datatracker.ietf.org/doc/html/rfc7636解决方案
-
Implement PKCE in the authorization request by generating a code_verifier (random string) and its SHA-256 hash as code_challenge, then send code_challenge_method=S256. Example in JavaScript: const codeVerifier = crypto.randomBytes(32).toString('base64url'); const codeChallenge = crypto.createHash('sha256').update(codeVerifier).digest('base64url'); Then include code_challenge and code_challenge_method in the authorization request, and send code_verifier in the token request. -
Enable PKCE enforcement on the authorization server (e.g., in Auth0 tenant settings under 'Advanced OAuth' > 'OIDC Conformant').
-
Upgrade to OAuth2 libraries that enforce PKCE by default (e.g., Spring Security 5.7+ with oauth2Login).
无效尝试
常见但无效的做法:
-
60% 失败
Enabling HTTPS only protects the transport layer; the authorization code can still be intercepted via malicious redirects or browser extensions, as PKCE is a separate mechanism.
-
70% 失败
Using state parameter alone is insufficient because if the attacker can predict or steal the state, they can still inject the code; PKCE uses a cryptographically random code verifier that cannot be guessed.
-
50% 失败
Shortening the authorization code lifetime reduces the window for attack but does not prevent injection; PKCE is the only standard mitigation.