我正在尝试使用 JWT 为我的 RESTful API 实现无状态身份验证。
AFAIK,JWT 基本上是在 REST 调用期间作为 HTTP 标头传递的加密字符串。
但是如果有窃听者看到请求并窃取令牌怎么办?那他就可以用我的身份伪造请求了?
实际上,这种担忧适用于所有基于令牌的身份验证。
如何防止这种情况?像 HTTPS 这样的安全通道?
having finer control of token expiration
和 having better scalability
之间的 trade-off
。
我是一个节点库的作者,该库处理相当深入的身份验证,express-stormpath,所以我将在这里附上一些信息。
首先,JWT 通常是不加密的。虽然有一种加密 JWT 的方法(请参阅:JWEs),但由于许多原因,这在实践中并不常见。
接下来,任何形式的身份验证(使用或不使用 JWT)都会受到 MitM 攻击(中间人)攻击。当攻击者可以在您通过 Internet 发出请求时查看您的网络流量时,就会发生这些攻击。这是您的 ISP、NSA 等可以看到的内容。
这是 SSL 有助于防止的:通过加密来自您计算机的网络流量 -> 身份验证时的某些服务器,监控您的网络流量的第三方无法看到您的令牌、密码或类似的东西,除非他们能够以某种方式获取服务器的私有 SSL 密钥的副本(不太可能)。这就是所有形式的身份验证都必须使用 SSL 的原因。
但是,假设有人能够利用您的 SSL 并能够查看您的令牌:您的问题的答案是肯定的,攻击者将能够使用该令牌冒充您并向您的服务器发出请求。
现在,这就是协议的用武之地。
JWT 只是身份验证令牌的一种标准。它们几乎可以用于任何事情。 JWT 有点酷的原因是您可以在其中嵌入额外的信息,并且您可以验证没有人弄乱它(签名)。
但是,JWT 本身与“安全”无关。出于所有意图和目的,JWT 或多或少与 API 密钥相同:只是用于在某处对某些服务器进行身份验证的随机字符串。
使您的问题更有趣的是正在使用的协议(很可能是 OAuth2)。
OAuth2 的工作方式是,它旨在为客户端提供临时令牌(如 JWT!),仅在短时间内进行身份验证!
这个想法是,如果您的令牌被盗,攻击者只能在短时间内使用它。
使用 OAuth2,您必须经常通过提供您的用户名/密码或 API 凭据来重新对服务器进行身份验证,然后获取一个令牌作为交换。
因为这个过程时不时发生,你的代币会经常改变,这使得攻击者更难不断冒充你而不会遇到很大的麻烦。
希望这会有所帮助^^
我知道这是一个老问题,但我认为我可以在这里放弃我的 0.50 美元,也许有人可以改进或提供完全拒绝我的方法的论据。我在通过 HTTPS (ofc) 的 RESTful API 中使用 JWT。
为此,您应该始终发出短期令牌(取决于大多数情况,在我的应用中,我实际上将 exp
声明设置为 30 分钟,将 ttl
声明设置为 3 天,因此您可以刷新此令牌只要它的 ttl
仍然有效并且令牌未被列入黑名单)
对于 authentication service
,为了使令牌无效,我喜欢使用内存缓存层(在我的例子中为 redis)作为前面的 JWT blacklist
/ban-list
,具体取决于某些标准:(我知道它违反了 RESTful 哲学,但存储的文档确实是短暂的,因为我将它们的剩余生存时间列入黑名单 -ttl
声明 -)
注意:列入黑名单的令牌不能自动刷新
如果 user.password 或 user.email 已更新(需要密码确认),身份验证服务会返回一个刷新的令牌并使之前的令牌无效(黑名单),因此如果您的客户端检测到用户的身份已被某种方式泄露,您可以询问该用户更改其密码。如果您不想为此使用黑名单,您可以(但我不鼓励您)验证针对 user.updated_at 字段的 iat(发布于)声明(如果 jwt.iat < user.updated_at 则 JWT 是无效)。
用户故意退出。
最后,您像每个人一样正常验证令牌。
注意 2: 我建议不要使用令牌本身(它真的很长)作为缓存的键,而是为 jti
声明生成和使用 UUID 令牌。哪个好,我认为(不确定,因为它刚刚出现在我的脑海中)您也可以使用与 CSRF 令牌相同的 UUID,方法是返回一个 secure
/ non-http-only
cookie 并正确实现 {4 } 标头使用 js。这样您就可以避免为 CSRF 检查创建另一个令牌的计算工作。
抱歉在这方面有点晚了,但有类似的担忧,现在想为此做出贡献。
1) rdegges 添加了一个很好的观点,JWT 与“安全”无关,只是验证是否有人弄乱了有效负载(签名); ssl 有助于防止违规。
2)现在,如果 ssl 也以某种方式受到损害,任何窃听者都可以窃取我们的不记名令牌(JWT)并冒充真实用户,下一步可以做的是从客户端寻求 JWT 的“拥有证明” .
3) 现在,通过这种方法,JWT 的提交者拥有一个特定的 Proof-Of-Possession (POP) 密钥,接收者可以cryptographically确认请求是否来自同一真实用户。
我为此参考了 Proof of Possesion 文章,并且对这种方法深信不疑。
如果能够贡献任何东西,我会很高兴。
干杯(y)
为了解决令牌被盗的问题,您将每个 JWT 映射到有效 IP 列表。
例如,当用户使用特定 IP 登录时,您可以将该 IP 添加为该 JWT 的有效 IP,并且当您从另一个 IP 获得此 JWT 的请求时(用户更改互联网或 JWT 被盗,或任何原因)您可以根据您的用例执行以下操作:
将 CSRF 令牌与用户令牌映射,以防万一它被盗,那么它的 CSRF 令牌将不匹配,因为您可以使该用户令牌无效。您可以向用户提供验证码以验证他是否是有效用户。如果他输入验证码,则将该 IP 添加到该 JWT 的有效列表中。您可以注销用户并发出新请求以再次登录。您可以提醒用户您的 IP 已更改或从其他位置请求。
建议是否可以改进。
我们不能只添加请求生成此 JWT 令牌的初始主机的 ip 作为声明的一部分吗?现在,当 JWT 被盗并从另一台机器上使用时,当服务器验证此令牌时,我们可以验证请求的机器 ip 是否与作为声明一部分的一组匹配。这将不匹配,因此可以拒绝令牌。此外,如果用户尝试通过将自己的 ip 设置为令牌来操纵令牌,则令牌将在令牌被更改时被拒绝。
一旦令牌被盗 - 游戏就结束了。但是,有一种方法可以使使用被盗令牌变得更加困难。
基本上,您以十六进制创建一个 x 字节长的指纹,将其原始值存储在令牌中 - 使用例如 SHA-512 对指纹进行散列,并将散列后的指纹放入 httponly 安全 cookie 中。
现在,您不仅需要验证令牌的签名和过期日期,还需要验证 cookie 的存在并确保原始指纹值匹配。
客户端应使用用户密码的部分哈希值来加密客户端向服务器发送 http msg 的时间。这部分哈希也应该在创建令牌时使用一些服务器密钥加密到令牌中。
服务器可以解密http请求时间并验证短时间延迟。
令牌将更改每个请求。
不定期副业成功案例分享