如何防止使用被盗令牌进行 Rest Web 服务身份验证

How to prevent Rest web-service Authentication with stolen Token

我们知道 Rest 服务是无状态的,一般的身份验证策略是使用基于令牌的身份验证。

在登录服务中,它需要 returns 令牌的凭据。

此令牌可能设置在客户端 cookie 中,所有后续请求都使用此令牌进行验证,如果令牌有效则处理新请求。

现在我的问题是如何验证令牌?如果有人窃取了令牌并试图通过仅编辑 cookie 来使用窃取的令牌访问休息服务,那么如何识别和限制它?

我们永远无法知道令牌是否由有效用户获取并且同一用户正在尝试访问后续请求。但是有什么方法可以让它变得更难,比如验证请求是否来自同一来源?

一个普遍的建议是为 token/cookies 设置老化,但直到 token/cookies 的年龄它仍然没有帮助。

如有任何建议,我们将不胜感激。

我不相信有任何 100% 万无一失的方法可以防止被盗用户令牌访问。你怎么知道令牌首先被盗了?但从我的脑海中你可能想考虑以下内容:

  1. 使用相同的令牌但不同的用户代理访问 REST 服务是可疑的。这可以通过 User-Agent header 的值来识别。您可能要考虑放弃此类请求。
  2. 如果IP地址变了但是token还是一样怎么办?好吧,也许有人正在使用负载均衡器并通过不同的 IP 地址访问网络?或者他访问了与之前相同的 token/cookie 的 VPN?如果您对丢弃此类请求没有任何顾虑,您也可以通过检查源 IP 地址来提高安全性。
  3. 如果是 JWT 令牌,您将需要一些基础设施来处理黑名单。关注 this.

我目前对在浏览器中授权请求的 "most secure" 方法的理解是要求验证 HttpOnly SameSite cookie 和 HTTP header(例如 AuthorizationX-CSRF-Token) 组合。

例如,向浏览器下发JWT时,将JWT签名发送到HttpOnly SameSite cookie中,将body(无签名)发送到客户端存储在localStorage 并在 Authorization header 中提交。授权请求时,将两者组合回完整的JWT,然后验证正常。

或者,您可以生成两个带有字段的 JWT 来区分它们(例如,客户端其中有 "browser",cookie 中有 "cookie")并要求两者都有效并且都标识同一个用户。一个在 Authorization header 中发送并存储在 localStorage 中,另一个使用 SameSite HttpOnly cookie。

另一种流行的方法是在 JWT 的一个字段中存储一个 CSRF 令牌,并将 JWT 放入一个 cookie 中,并要求客户端在 header 中发送一个匹配的令牌(例如 X-CSRF-Token).

所有的解决方案都有效地防止了 XSS 和 CSRF 攻击:XSS 无法检索 HttpOnly cookie,CSRF 不包括 HTTP header,因此这两种攻击都被阻止了。

请注意,您可能只想将此规则应用于来自网络浏览器的请求。对于 server-to-server 通信,请求不受 CSRF 和 XSS 攻击。

您可以使用 jwt 是一种互联网标准,用于创建基于 JSON 的访问令牌,这些令牌断言了一些声明。例如,服务器可以生成一个声明为 "logged in as admin" 的令牌并将其提供给客户端。然后客户端可以使用该令牌来证明它是以 admin 身份登录的。

它是如何工作的?

首先它包含开发者生成的私钥:

让我们有这个密钥:sfcqw@sav%$#fvcxv*s_s515 这个叫做私钥,我们还有一个 public 密钥,这个 public 密钥生成取决于用户数据和私钥如果您不知道私钥,就不可能知道其中包含什么。

更多解释:

public 键:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.plpJkAcgrgCIsoRyV2kjGsvWF6OsXU1mD785OSWTH4o

我们有私钥生成的上述密钥:sfcqw@sav%$#fvcxv*s_s515 要更清楚地访问此网站:https://jwt.io/ 并尝试通过 public 密钥而不像图片那样放置密钥,您将了解所有内容。

对我来说,除了

,没有办法防止访问被盗取 JWT 令牌
  • 为令牌设置一个短超时
  • 通过仅允许特定的 `User-Agent,在 HTTP 请求级别更加安全。 See more
  • 通过为组织自定义 header 密钥,在 HTTP 请求级别更加安全,例如 My-X-Auth = Bearer <token> 而不是 Authorization= Bearer <token>
  • 通过限制受信任 urls/domains 在 HTTP 请求级别更加安全,例如 X-Content-Security-PolicySee more

经过各种方法的努力后,我们找到了下面解释的解决方案:

  1. 我们根据登录请求将令牌(加密)存储在 cookie 中,并且对于每个后续请求,此 cookie 都会得到验证。
  2. 问题是如果有人将 cookie 中的令牌替换为另一个有效令牌,因为 cookie 是由客户端浏览器维护的。

解决方案:-> 虽然令牌值是加密的,但它只代表一个值,所以如果用另一个有效的加密值替换整个加密值,它就可以被黑客攻击。

因此,为了解决这个问题,我们添加了另一个 cookie,它是多个值的组合。

例如

Cookie 1 -> 加密令牌

Cookie 2 -> 包含用户名+一些其他用户上下文详细信息+令牌等信息的加密对象

所以在 Cookie 1 的情况下,很容易用另一个加密值替换,因为它只代表一个令牌,尽管它是加密的。

但在 Cookie 2 的情况下,它包含具有多个值的对象,因此不能在同一个 cookie 中修改、加密和设置回唯一的令牌值。

身份验证之前我们正在对整个 cookie 2 进行解密,从中获取令牌部分并根据 cookie 1 验证其令牌部分。

解决了我们的问题!!

感谢大家的宝贵时间和指导。