我目前正在 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 有效负载数据仍然可以随意更改。