【问题标题】:CSRF Token necessary when using Stateless(= Sessionless) Authentication?使用无状态(= 无会话)身份验证时需要 CSRF 令牌吗?
【发布时间】:2014-02-16 21:27:16
【问题描述】:

当应用程序依赖无状态身份验证(使用 HMAC 之类的东西)时,是否有必要使用 CSRF 保护?

例子:

  • 我们有一个单页应用程序(否则我们必须在每个链接上附加令牌:<a href="...?token=xyz">...</a>

  • 用户使用POST /auth 对自己进行身份验证。成功验证后,服务器将返回一些令牌。

  • 令牌将通过 JavaScript 存储在单页应用程序内的某个变量中。

  • 此令牌将用于访问受限 URL,例如 /admin

  • 令牌将始终在 HTTP 标头中传输。

  • 没有 Http 会话,也没有 Cookie。

据我了解,应该(?!)不可能使用跨站点攻击,因为浏览器不会存储令牌,因此它无法自动将其发送到服务器(这就是当使用 Cookie/会话)。

我错过了什么吗?

【问题讨论】:

  • 注意基本身份验证。许多浏览器会自动为会话的其余部分发送基本的身份验证标头。这会使基本身份验证与 cookie 身份验证一样容易受到 CSRF 的攻击。

标签: authentication csrf single-page-application stateless csrf-protection


【解决方案1】:

我发现了一些关于 CSRF + 使用 no cookie 进行身份验证的信息:

  1. https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/
    “由于您不依赖 cookie,因此您无需防范跨站点请求”

  2. http://angular-tips.com/blog/2014/05/json-web-tokens-introduction/
    “如果我们采用 cookie 方式,您确实需要执行 CSRF 以避免跨站点请求。正如您将看到的,在使用 JWT 时我们可以忘记这一点。”
    (JWT = Json Web Token, a无状态应用的基于令牌的身份验证)

  3. http://www.jamesward.com/2013/05/13/securing-single-page-apps-and-rest-services
    “在不冒 CSRF 漏洞风险的情况下进行身份验证的最简单方法是简单地避免使用 cookie 来识别用户”

  4. http://sitr.us/2011/08/26/cookies-are-bad-for-you.html
    “CSRF 的最大问题是 cookie 对此类攻击完全没有防御。如果您使用 cookie 身份验证,您还必须采取额外措施来防止 CSRF。您可以采取的最基本的预防措施是确保您的应用程序从不执行任何副作用来响应 GET 请求。”

如果您不使用 cookie 进行身份验证,还有很多页面表明您不需要任何 CSRF 保护。当然,您仍然可以将 cookie 用于其他所有内容,但避免在其中存储 session_id 之类的内容。


如果您需要记住用户,有两种选择:

  1. localStorage:浏览器内的键值对存储。即使在用户关闭浏览器窗口后,存储的数据仍然可用。其他网站无法访问这些数据,因为每个网站都有自己的存储空间。

  2. sessionStorage: 也是浏览器数据存储。不同之处在于:当用户关闭浏览器窗口时,数据会被删除。但如果您的 web 应用程序包含多个页面,它仍然很有用。因此,您可以执行以下操作:

  • 用户登录,然后您将令牌存储在sessionStorage
  • 用户单击一个链接,该链接会加载一个新页面(= 真实链接,并且没有 javascript 内容替换)
  • 您仍然可以从sessionStorage 访问令牌
  • 要注销,您可以手动从sessionStorage 中删除令牌或等待用户关闭浏览器窗口,这将清除所有存储的数据。

(两者都看这里:http://www.w3schools.com/html/html5_webstorage.asp


令牌认证有什么官方标准吗?

JWT(Json Web Token):我觉得还是一个草稿,但是已经被很多人使用了,概念看起来简单又安全。 (IETF:https://datatracker.ietf.org/doc/html/draft-ietf-oauth-json-web-token-25
还有许多可用框架的库。只需谷歌即可!

【讨论】:

  • 关于 CSRF 的精彩总结!我会注意到,将您的令牌存储在 localStorage 或 sessionStorage 中容易受到 XSS 攻击,并且可以通过页面上的脚本查看数据 - 因此,如果您有一个从 CDN 提供的受损脚本,或者您的其中一个中有恶意代码JS 库,他们可以从这些存储位置窃取令牌。请参阅:stormpath.com/blog/… 我认为最安全的方法是将 JWT + CSRF 令牌存储在 cookie 中,然后将计算出的 JWT 和 CSRF 令牌放入请求标头中。
  • 关于:“您可以采取的最基本的预防措施是确保您的应用程序在响应 GET 请求时永远不会执行任何副作用。” CSRF 攻击是否有可能伪造 POST 请求?
  • 取决于服务器端应用程序,它是可能的。有一些 Web 框架,它们使用 http://.../someRestResource?method=POST 之类的东西。所以它基本上是一个GET 请求,但是服务器应用程序将它解释为一个POST 请求,因为它被配置为使用method 参数而不是HTTP 标头。 ... 对于常见的网络浏览器,它们执行同源策略,并且只会执行GET 对外部服务器的请求。虽然可能可以执行POST请求如果网络浏览器不应用这些网络标准(错误、恶意软件)。
  • Server Side App 的补充:仍然无法发送请求正文,因为普通浏览器不允许这样做。但是,如果服务器应用程序允许 method=POST,它也可能允许 body={someJson} 覆盖默认请求正文。这是非常糟糕的 API 设计,而且风险极大。尽管如果您的服务器应用程序允许 http://...?method=POST&body={someJson} 您真的应该过度考虑您在那里做了什么以及为什么以及是否有必要。 (我会说在 99,9999% 的情况下它没有是必要的)。此外,浏览器只能通过这种方式发送几千字节。
  • @BenjaminM 注意到,同源策略仅阻止 JavaScript 代码访问结果,因此当请求被“阻止”时,它实际上到达了服务器 - jsbin.com/mewaxikuqo/edit?html,js,output 我只在 Firefox 上测试了这个,但是你可以打开开发工具并看到即使你得到“跨源请求被阻止”,远程服务器实际上也能看到整个请求。这就是为什么您必须为所有 POST 请求提供令牌或自定义标头(如果可能的话,两者都需要)
【解决方案2】:

TL;DR

如果在没有 Cookie 的情况下使用 JWT,则不需要 CSRF 令牌 - 但是!通过将 JWT 存储在 session/localStorage 中,如果您的站点存在 XSS 漏洞(相当常见),您将暴露您的 JWT 和用户身份。最好在 JWT 中添加一个csrfToken 密钥,并将 JWT 存储在设置了 securehttp-only 属性的 cookie 中。

阅读这篇带有详细描述的文章以获取更多信息 https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage

您可以通过包含 xsrfToken JWT 声明使此 CSRF 保护无状态:

{ "iss": "http://galaxies.com", "exp": 1300819380, "scopes": ["explorer", "solar-harvester", "seller"], "sub": "tom@andromeda.com", "xsrfToken": "d9b9714c-7ac0-42e0-8696-2dae95dbc33e" }

因此,您需要将 csrfToken 存储在 localStorage/sessionStorage 以及 JWT 本身(存储在仅 http 且安全的 cookie 中)。然后对于 csrf 保护,验证 JWT 中的 csrf 令牌是否与提交的 csrf-token 标头匹配。

【讨论】:

  • 是否应该在用户的 api 身份验证期间豁免 csrf 令牌使用?
  • 值得指出(正如其他人在源链接的 cmets 中也提到的那样)任何 CSRF 缓解使用 a) cookie,不是仅 http 或 b) 将 CSRF 令牌存储在本地存储易受 XSS 攻击。这意味着所提出的方法可以帮助使用 XSS 的攻击者对 JWT 保密,但攻击者仍然能够在您的 API 上执行恶意请求,因为他能够提供有效的 JWT(通过 cookie,谢谢浏览器)和 CSRF 令牌(通过注入的 JS 从本地存储/cookie 读取)。
  • 实际上,即使是 CSRF 令牌也无法在此级别的 XSS 中保护您,因为您假设攻击者可以访问 localStorage,目前唯一的访问方式是拥有脚本级别的访问权限,他们可以无论如何,看看 CSRF 令牌。
  • 这不是@JohannesRudolph 所说的吗?一旦您将 CSRF 令牌存储在 Web 存储/非 http-only cookie 中,您就会增加 XSS 攻击的足迹,因为这些可以通过 JS 访问。
  • 这里不是完全的专家,但如果你仍然像一开始一样接触到 XSS,我不确定部分 最好添加... i> 真的成立。攻击者获取 CSRF 令牌可能会稍微复杂一点(?),但最终他仍然能够代表您执行请求,即使实际上不知道 JWT 令牌。那是对的吗?谢谢
猜你喜欢
  • 1970-01-01
  • 2015-08-30
  • 2017-08-03
  • 2017-01-01
  • 2014-07-09
  • 1970-01-01
  • 2017-01-28
  • 2015-10-09
  • 2017-05-19
相关资源
最近更新 更多