OAuth 2.0 PKCE 模式:移动应用的安全授权
PKCE(Proof Key for Code Exchange)是OAuth 2.0的安全扩展,专为移动应用和单页应用设计,用于防止授权码截获攻击。核心原理是通过动态生成的密钥对验证请求合法性。
核心概念
-
Code Verifier
客户端生成的随机字符串,满足:- 长度:43-128字符
- 字符集:$[A-Z]$, $[a-z]$, $[0-9]$, $_$, $\cdot$, $-$, $\sim$
$$ \text{code_verifier} \in {c \mid ASCII(c) \in [65,90] \cup [97,122] \cup [48,57] \cup {45,46,95,126}} $$
-
Code Challenge
Verifier的变换值,支持两种方式:- S256(推荐):$ \text{code_challenge} = \text{base64url}( \text{SHA256}( \text{code_verifier} ) ) $
- plain:直接使用原始verifier
工作流程
sequenceDiagram
participant App as 移动应用
participant AS as 授权服务器
participant RS as 资源服务器
App->>App: 生成 code_verifier
App->>App: 计算 code_challenge
App->>AS: 授权请求 (含 code_challenge)
AS-->>App: 返回授权码
App->>AS: 令牌请求 (含 code_verifier)
AS->>AS: 验证 challenge = SHA256(verifier)
AS->>App: 颁发访问令牌
App->>RS: 携带令牌访问API
安全优势
-
防止授权码劫持
攻击者截获授权码后,因缺少$ \text{code_verifier} $无法兑换令牌。 -
动态密钥保护
每次请求生成新的$ (\text{verifier}, \text{challenge}) $对,满足:
$$ P(\text{碰撞}) \leq 2^{-128} \quad (\text{SHA-256安全性}) $$ -
客户端认证增强
即使客户端密钥泄露,攻击者仍需原始$ \text{code_verifier} $才能完成流程。
实现示例(Python)
import hashlib
import base64
import secrets
# 生成code_verifier
def gen_verifier(length=64):
charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"
return ''.join(secrets.choice(charset) for _ in range(length))
# 生成S256 challenge
def gen_challenge(verifier):
sha256 = hashlib.sha256(verifier.encode()).digest()
return base64.urlsafe_b64encode(sha256).decode().replace('=', '')
# 使用示例
verifier = gen_verifier()
challenge = gen_challenge(verifier)
print(f"Verifier: {verifier}\nChallenge: {challenge}")
最佳实践
- 强制使用S256:避免
plain模式降低安全性 - verifier存储:客户端会话期间安全保存
- 令牌生命周期:访问令牌有效期 ≤ 1小时,配合刷新令牌
- 符合RFC 7636:遵循标准实现互操作性
PKCE已成为OAuth 2.0安全实践的必备组件,尤其适用于无法安全存储客户端密钥的移动/桌面应用场景。
1899

被折叠的 条评论
为什么被折叠?



