我正在实现一个需要身份验证的 REST 服务。我无法存储任何每个用户的状态(例如随机生成的令牌),因为我的服务无法直接访问数据库,只能访问另一个后端服务。
我想出的解决方案是在用户进行身份验证时创建一个 JSON Web Token ( JWT )。JWT 声明集在主题(“子”)字段中包含用户 ID。然后,服务器使用 AES GCM 和 256 位密钥(“enc”:“A256GCM”)直接加密声明集(“alg”:“dir”),创建JWE。密钥在服务启动时生成一次并存储在内存中。
为了进行身份验证,客户端提交用户名/密码,服务器使用上述令牌进行响应。然后客户端随每个后续请求发送该令牌。
当客户端通过后续请求提交令牌时,服务器使用密钥对其进行解密,并假定“子”字段中的用户 ID 为当前用户的 ID,无需任何进一步的身份验证检查。令牌过期由 JWT 声明集中的“exp”字段处理。
客户端和服务器之间的连接将使用 SSL/TLS,因此令牌不会泄漏。
我正在使用这个库来创建和读取 JWT,因为我不相信自己会编写正确的加密代码。
我的问题:
- 上述方法安全吗?攻击者可以通过操纵令牌来冒充另一个用户吗?
- 方法是否过于复杂?使用 MAC(换句话说:JWS)而不是加密是否具有相同的安全性?(或者可能更多,因为它更简单并且出错的可能性更小)。JWT 声明集中没有什么特别秘密的,用户知道自己的 ID 并不重要。
- 我选择的 JWE 算法和加密是否合适?
- 对于 JWE “alg”,我使用的库支持直接加密(直接使用密钥加密声明集)和 RSA(生成新密钥来加密每个令牌的声明集,并使用生成的密钥加密RSA 公钥)。我选择前者是因为生成对称密钥比生成 RSA 密钥更容易。
- 对于 JWE “enc”,该库支持 AES GCM 和 AES CBC HMAC SHA2(具有各种位长)。我随意选择了GCM。