使用带有 HMAC 的 JWT 进行身份验证时的共享密钥

信息安全 验证 hmac jwt
2021-08-16 05:52:58

我目前正在 Android 客户端使用的类似 REST 的 API 上实现用户身份验证。经过一些研究,我认为 JWT (JSON Web Token) 是一个很好的方法。

我计划的基本程序是:用户使用用户名/密码(通过 HTTPS)登录。服务器验证密码,然后生成一个包含某种用户 ID 的 JWT,使用 RS256(使用 RSA 非对称,因此客户端只有相应的公钥)对其进行签名,并将其发送给客户端。要进行 API 调用,客户端会将 JWT 发送到服务器。然后,服务器所做的就是使用其私钥验证 JWT,并检查签名算法是否是服务器所期望的。如果验证成功,服务器可以信任令牌中的用户 ID。客户端不能假装是不同的用户,因为如果 JWT 的有效负载发生更改,它需要服务器的私钥来生成正确的签名。

现在假设我想改用 HS256(使用 HMAC 对称),可能是因为生成的签名更短。就我的常识而言,在这种情况下,只允许服务器知道(单个)密钥。

但这里出现了困惑:阅读使用 HS256 和 JWT,我看到的一些网站似乎暗示密钥是“共享密钥”,这意味着服务器和客户端都知道它。但如果是这种情况,客户端可以简单地更改 JWT 的有效负载并使用共享密钥创建有效签名。然后,任何登录用户都可以通过简单地更改 JWT 中的用户 ID 来伪装成任何其他用户,所以这并不比根本不验证签名好。是我遗漏了什么,还是在使用 HS256 时允许客户端访问密钥根本没有意义?我是否误读了建议共享 HS256 密钥的网站?

我能想到的唯一方法是让双方都知道密钥是为每个用户使用单独的密钥。但即便如此,除了用户 ID(例如“isAdmin”标志)之外的任何 JWT 有效负载数据仍然可以随意更改。

1个回答

在这种情况下,“共享密钥”通常是指在多个服务器之间,而不是在客户端和服务器之间。通常,JWT 可以使用对称加密来完成 - 在这种情况下,所有需要验证令牌的服务器都需要具有共享密钥 - 或非对称加密,在这种情况下,只有实际进行身份验证的服务器需要拥有私钥,即其他服务器可以只使用公钥来验证令牌是否已正确签名。

在任何情况下,客户端都不能更改其令牌 - 他们在提供凭据时接收令牌,然后使用令牌从同一服务器或从与授权服务器共享信任关系的其他服务器获取服务(通过公钥/私钥知识或通过共享密钥)