【问题标题】:Why does Spring's default OAuth JWT implementation make the JWT verifier public?为什么 Spring 默认的 OAuth JWT 实现会公开 JWT 验证器?
【发布时间】:2017-11-18 18:07:26
【问题描述】:
Spring默认的OAuth JWT流(使用client_credentials授权)如下:
- 启动身份验证服务器 (AS)
- 启动资源服务器 (RS)
- 在启动时,RS 通过使用基本身份验证调用
GET /oauth/token_key 来请求 tokenKey
- AS 使用 RS256 (SHA256withRSA) 返回一个 PUBLIC KEY
- 一段时间后,客户端通过使用 client_credentials 授权调用
GET /oauth/token 请求 accessToken
- AS 返回一个包含JWS signature 的JWT accessToken
- 客户端将 JWT 作为承载令牌发送到 RS
- RS 使用它在启动时从 AS 收到的 tokenKey 来验证 JWT accessToken 是否来自 AS。这就是我感到困惑的地方......
这安全吗?为什么要使用公共证书而不是共享密钥?黑客不能轻松获取公钥并签署自己的有效 JWT accessToken 吗?公钥证书和 JWT 签名的使用如何共同验证发送者实际上是 Auth Server 而不是攻击者?
任何见解都会有所帮助。
【问题讨论】:
标签:
jwt
public-key-encryption
spring-security-oauth2
hmac
【解决方案1】:
一些对公钥密码学和数字签名性质的研究收集了这一点:
数字签名实现非对称加密。数字签名使接收者有理由相信消息是由声称的发送者发送的。与手写签名类似,它们很难伪造。签名者(在本例中为 AS)使用秘密 PrivateKey 来创建签名。一些不可否认方案为数字签名提供时间戳,这样即使 PrivateKey 暴露,签名也是有效的。
一个数字签名方案通常由 3 种算法组成
1) key generation algorithm 从一组可能的私钥中随机均匀地选择一个 PrivateKey。算法输出私钥和对应的公钥。
2) 使用消息和私钥创建签名的signing algorithm
3) 一个signature verifying algorithm,根据消息、PublicKey 和签名,接受或拒绝消息的真实性声明。
在这种情况下(RS256),签名是使用 SHA256withRSA 创建的,它不用作加密算法,而是用于验证数据的来源或真实性。签名是使用私钥生成的。公钥被传递到资源服务器以用于验证签名。在这种情况下,即使攻击者拥有 PublicKey,他们也无法创建带有签名的欺骗消息或更改内容。