题目
设计一个安全的OAuth 2.0授权码流程实现并防御常见漏洞
信息
- 类型:问答
- 难度:⭐⭐⭐
考点
OAuth 2.0协议安全, CSRF防护, PKCE机制, 重定向URI验证, 令牌安全存储
快速回答
安全实现OAuth 2.0授权码流程需包含:
- 强制使用PKCE(Proof Key for Code Exchange)防止授权码截获攻击
- 严格验证重定向URI(包括完整路径匹配和注册白名单)
- 实施CSRF令牌保护授权请求
- 访问令牌短期化并采用JWT签名验证
- 敏感数据安全存储(使用HttpOnly+Secure Cookie和内存存储)
1. 核心漏洞场景
OAuth 2.0常见攻击面:
- 授权码截获:攻击者拦截授权码通过未验证客户端兑换令牌
- 开放重定向:恶意重定向URI泄露令牌或授权码
- CSRF攻击:诱导用户使用攻击者账户授权
- 令牌泄露:XSS攻击窃取存储不当的令牌
2. 安全实现方案
2.1 PKCE防护(RFC 7636)
# 客户端生成PKCE参数
import hashlib, base64, os
code_verifier = base64.urlsafe_b64encode(os.urandom(32)).rstrip(b'=').decode()
code_challenge = hashlib.sha256(code_verifier.encode()).digest()
code_challenge = base64.urlsafe_b64encode(code_challenge).rstrip(b'=').decode()
# 授权请求URL示例
redirect_url = (
"https://auth-server.com/authorize?"
"response_type=code&"
"client_id=CLIENT_ID&"
"redirect_uri=https://client.com/callback&"
"code_challenge=" + code_challenge + "&"
"code_challenge_method=S256"
)服务端验证:兑换令牌时校验code_verifier的SHA256摘要是否匹配初始challenge
2.2 重定向URI严格验证
// 服务端验证逻辑示例
public boolean validateRedirectUri(String requestedUri, String registeredUri) {
// 1. 完全匹配注册URI
if (!requestedUri.equals(registeredUri)) {
// 2. 禁止开放重定向(拒绝非白名单域名)
if (!isAllowedDomain(requestedUri)) {
return false;
}
// 3. 路径遍历防护
if (requestedUri.contains("..") || requestedUri.contains("%")) {
return false;
}
}
return true;
}2.3 CSRF防护
在授权请求中添加绑定会话的state参数:
// 生成并存储state
const state = crypto.randomBytes(16).toString('hex');
sessionStorage.setItem('oauth_state', state);
// 回调时验证
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.get('state') !== sessionStorage.getItem('oauth_state')) {
throw new Error("CSRF detected");
}3. 令牌安全实践
- 访问令牌:设为短期(e.g. 15-30分钟),使用JWT签名验证
- 刷新令牌:
- 绑定客户端指纹(ip+user-agent)
- 单次使用后立即撤销
- 服务端内存存储(非数据库)
- 客户端存储:
Set-Cookie: refresh_token=xxx; HttpOnly; Secure; SameSite=Strict; Path=/token-refresh
4. 常见错误
- ❌ 允许任意重定向URI(导致开放重定向)
- ❌ 未校验客户端身份(允许任意兑换授权码)
- ❌ 令牌长期有效且无范围限制
- ❌ 在URL片段中传递令牌(可能被日志记录)
5. 扩展知识
- OAuth 2.1规范:强制PKCE和精确重定向URI匹配
- JWT最佳实践:
- 使用RS256而非HS256(避免密钥泄露)
- 明确设置令牌过期时间(exp claim)
- 进阶防护:
- 动态客户端注册(RFC 7591)
- 令牌绑定(Token Binding)
- 持续访问评估(FAPI标准)