Demonstrating Proof of Possession (DPoP) 是一个现代 OAuth 2.0 安全扩展(定义于 RFC 9449),旨在防止访问令牌被窃取后用于重放攻击,它通过密码学手段将令牌“绑定”到发起请求的特定客户端上。
1. 核心原理:从“持有者”到“发送方约束”
传统的 OAuth 2.0 令牌是不记名令牌。这意味着只要 possessing the token,任何客户端(如浏览器、API 调用工具)都可以使用它。如果令牌在传输过程中被窃取或日志泄露,攻击者可以立即冒充合法用户。
DPoP 将不记名令牌转变为发送方约束令牌,其原理如下:
- 生成密钥对:客户端在发起授权请求前,首先生成一个临时的非对称密钥对(公钥和私钥)。
- 签署证明:客户端使用私钥生成一个 JSON Web Token (JWT),这个 JWT 称为 DPoP Proof。该 JWT 包含了当前的 HTTP 方法、目标 URL 和时间戳等信息。
- 绑定公钥:客户端将 DPoP Proof 发送给授权服务器。服务器验证签名后,将公钥嵌入到颁发的 Access Token 中。
- 验证请求:当客户端使用 Access Token 请求资源时,必须再次生成一个新的 DPoP Proof。资源服务器不仅校验 Token 是否过期,还必须校验该 Proof 中的签名是否与 Token 中绑定的公钥匹配,且 Proof 中的 URL 与请求 URL 一致。
2. 技术实现细节
实施 DPoP 需要在 HTTP 请求头中携带特定的 JWT:
- 请求头:客户端必须添加名为
DPoP的 Header。 - JWT 结构:
- Header:必须包含
typ: "dpop+jwt",以及用于验证的jwk(公钥)字段。 - Payload:必须包含以下声明以防止重放和劫持:
htm:HTTP 方法(如POST或GET)。htu:请求的 URL(必须为完整 URL,不含片段)。jti:唯一标识符(每次请求都必须随机生成,防止重放攻击)。iat/exp:签发时间和过期时间(有效期通常很短,如 60 秒)。ath:Access Token Hash(当请求资源服务器时必须包含),值是 Access Token 的 SHA-256 哈希值,用于确保该 DPoP Proof 只针对当前的 Access Token 有效。
- Header:必须包含
3. 使用场景与优势
DPoP 主要用于无法使用或难以部署 mTLS(双向 TLS)的场景,特别是公共客户端:
- 单页应用:由于代码运行在浏览器中,无法像后端服务那样持有客户端证书,DPoP 通过 Web Crypto API 在浏览器内生成密钥对,可以极大缓解 XSS 攻击导致的令牌泄露风险。
- 移动应用/原生应用:DPoP 可以利用操作系统提供的安全硬件(如 Keystore/Keychain)来存储私钥,确保私钥不可导出,从而防止恶意应用读取令牌后伪造请求。
- 金融级 API:在 FAPI 2.0 等高安全要求的标准中,DPoP 是实现发送方约束令牌的推荐方式。
4. 安全提示
- 配合 TLS 使用:DPoP 并不能替代 HTTPS。它解决了“令牌被窃取后滥用”的问题,但不能解决中间人攻击窃取原始数据的问题,因此必须始终配合 TLS 使用。
- 防重放:虽然 DPoP 能防止令牌被复制后使用,但如果攻击者通过 XSS 直接在用户浏览器中执行代码,依然可以利用“合法”的客户端环境发送恶意请求。因此 DPoP 不能取代输入验证和内容安全策略(CSP)。
总而言之,DPoP 是一种深度的防御机制,它让 OAuth 2.0 的令牌脱离了“谁捡到谁使用”的不安全状态。
如果你正在开发 SPA 或移动应用,需要我详细介绍如何在具体代码中生成 DPoP Proof JWT 吗?
