为什么将 CSRF 预防令牌放在 cookie 中很常见? [英] Why is it common to put CSRF prevention tokens in cookies?

查看:36
本文介绍了为什么将 CSRF 预防令牌放在 cookie 中很常见?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试了解 CSRF 的整个问题以及防止它出现的适当方法.(我已阅读、理解并同意的资源:OWASP CSRF 预防作弊表格关于CSRF的问题.)

I'm trying to understand the whole issue with CSRF and appropriate ways to prevent it. (Resources I've read, understand, and agree with: OWASP CSRF Prevention CHeat Sheet, Questions about CSRF.)

据我所知,CSRF 的漏洞是由以下假设引入的:(从网络服务器的角度来看)传入 HTTP 请求中的有效会话 cookie 反映了经过身份验证的用户的意愿.但是原始域的所有 cookie 都被浏览器神奇地附加到请求中,因此实际上所有服务器都可以从请求中存在有效会话 cookie 中推断出该请求来自具有经过身份验证的会话的浏览器;它不能进一步假设关于在该浏览器中运行的代码,或者它是否真的反映了用户的意愿.防止这种情况的方法是在请求中包含额外的身份验证信息(CSRF 令牌"),通过浏览器的自动 cookie 处理以外的其他方式携带.粗略地说,会话 cookie 对用户/浏览器进行身份验证,CSRF 令牌对浏览器中运行的代码进行身份验证.

As I understand it, the vulnerability around CSRF is introduced by the assumption that (from the webserver's point of view) a valid session cookie in an incoming HTTP request reflects the wishes of an authenticated user. But all cookies for the origin domain are magically attached to the request by the browser, so really all the server can infer from the presence of a valid session cookie in a request is that the request comes from a browser which has an authenticated session; it cannot further assume anything about the code running in that browser, or whether it really reflects user wishes. The way to prevent this is to include additional authentication information (the "CSRF token") in the request, carried by some means other than the browser's automatic cookie handling. Loosely speaking, then, the session cookie authenticates the user/browser and the CSRF token authenticates the code running in the browser.

所以简而言之,如果您使用会话 cookie 来验证您的 Web 应用程序的用户,您还应该向每个响应添加一个 CSRF 令牌,并在每个(变异)请求中要求一个匹配的 CSRF 令牌.然后,CSRF 令牌从服务器到浏览器再到服务器的往返,向服务器证明发出请求的页面已被该服务器批准(甚至由该服务器生成).

So in a nutshell, if you're using a session cookie to authenticate users of your web application, you should also add a CSRF token to each response, and require a matching CSRF token in each (mutating) request. The CSRF token then makes a roundtrip from server to browser back to server, proving to the server that the page making the request is approved by (generated by, even) that server.

关于我的问题,这是关于在该往返中用于该 CSRF 令牌的特定传输方法.

On to my question, which is about the specific transport method used for that CSRF token on that roundtrip.

这似乎很常见(例如在 AngularJS 中,Django, Rails) 将 CSRF 令牌作为 cookie 从服务器发送到客户端(即在 Set-Cookie 标头中),然后客户端中的 Javascript 将其从cookie 并将其作为单独的 XSRF-TOKEN 标头附加到服务器.

It seems common (e.g. in AngularJS, Django, Rails) to send the CSRF token from server to client as a cookie (i.e. in a Set-Cookie header), and then have Javascript in the client scrape it out of the cookie and attach it as a separate XSRF-TOKEN header to send back to the server.

(另一种方法是例如 Express,其中由服务器生成的 CSRF 令牌通过服务器端模板扩展包含在响应正文中,直接附加到将其提供回服务器的代码/标记,例如作为隐藏的表单输入.那个例子是一种更像 web 1.0-ish 的做事方式,但可以很好地推广到更重 JS 的客户端.)

(An alternate method is the one recommended by e.g. Express, where the CSRF token generated by the server is included in the response body via server-side template expansion, attached directly to the code/markup that will supply it back to the server, e.g. as a hidden form input. That example is a more web 1.0-ish way of doing things, but would generalize fine to a more JS-heavy client.)

为什么使用 Set-Cookie 作为 CSRF 令牌的下游传输如此普遍/为什么这是个好主意?我想所有这些框架的作者都仔细考虑了他们的选择并且没有弄错.但乍一看,使用 cookie 来解决本质上是 cookie 的设计限制似乎很愚蠢.事实上,如果你使用 cookie 作为往返传输(Set-Cookie: header 下游的服务器告诉浏览器 CSRF 令牌,和 Cookie: header 上游的浏览器将其返回给服务器)你会重新引入你的漏洞正在尝试修复.

Why is it so common to use Set-Cookie as the downstream transport for the CSRF token / why is this a good idea? I imagine the authors of all these frameworks considered their options carefully and didn't get this wrong. But at first glance, using cookies to work around what's essentially a design limitation on cookies seems daft. In fact, if you used cookies as the roundtrip transport (Set-Cookie: header downstream for the server to tell the browser the CSRF token, and Cookie: header upstream for the browser to return it to the server) you would reintroduce the vulnerability you are trying to fix.

我意识到上面的框架没有在整个 CSRF 令牌的往返过程中使用 cookie;他们在下游使用 Set-Cookie,然后在上游使用其他东西(例如 X-CSRF-Token 标头),这确实关闭了漏洞.但即使使用 Set-Cookie 作为下游传输也有潜在的误导性和危险性;浏览器现在会将 CSRF 令牌附加到每个请求,包括真正的恶意 XSRF 请求;充其量这会使请求比它需要的更大,最坏的情况是一些善意但被误导的服务器代码实际上可能会尝试使用它,这将非常糟糕.此外,由于 CSRF 令牌的实际预期接收者是客户端 Javascript,这意味着该 cookie 不能仅使用 http 来保护.因此,在 Set-Cookie 标头中向下游发送 CSRF 令牌对我来说似乎不太理想.

I realize that the frameworks above don't use cookies for the whole roundtrip for the CSRF token; they use Set-Cookie downstream, then something else (e.g. a X-CSRF-Token header) upstream, and this does close off the vulnerability. But even using Set-Cookie as the downstream transport is potentially misleading and dangerous; the browser will now attach the CSRF token to every request including genuine malicious XSRF requests; at best that makes the request bigger than it needs to be and at worst some well-meaning but misguided piece of server code might actually try to use it, which would be really bad. And further, since the actual intended recipient of the CSRF token is client-side Javascript, that means this cookie can't be protected with http-only. So sending the CSRF token downstream in a Set-Cookie header seems pretty suboptimal to me.

推荐答案

一个很好的理由,你已经有点触及,是一旦收到 CSRF cookie,它就可以在客户端的整个应用程序中使用用于常规表单和 AJAX POST 的脚本.这在诸如 AngularJS 使用的 JavaScript 重应用程序中是有意义的(使用 AngularJS 并不要求应用程序是单页面应用程序,因此当状态需要在 CSRF 值的不同页面请求之间流动时会很有用不能正常在浏览器中持久化).

A good reason, which you have sort of touched on, is that once the CSRF cookie has been received, it is then available for use throughout the application in client script for use in both regular forms and AJAX POSTs. This will make sense in a JavaScript heavy application such as one employed by AngularJS (using AngularJS doesn't require that the application will be a single page app, so it would be useful where state needs to flow between different page requests where the CSRF value cannot normally persist in the browser).

请考虑典型应用程序中的以下场景和流程,了解您描述的每种方法的优缺点.这些基于 同步器令牌模式.

Consider the following scenarios and processes in a typical application for some pros and cons of each approach you describe. These are based on the Synchronizer Token Pattern.

  1. 用户成功登录.
  2. 服务器发出身份验证 cookie.
  3. 用户点击以导航到表单.
  4. 如果尚未为此会话生成,服务器会生成 CSRF 令牌,将其存储在用户会话中并将其输出到隐藏字段.
  5. 用户提交表单.
  6. 服务器检查隐藏字段是否与会话存储的令牌匹配.

优点:

  • 易于实施.
  • 使用 AJAX.
  • 使用表单.
  • Cookie 实际上可以是 HTTP Only.

缺点:

  • 所有表单都必须以 HTML 格式输出隐藏字段.
  • 任何 AJAX POST 也必须包含该值.
  • 页面必须事先知道它需要 CSRF 令牌,以便它可以将其包含在页面内容中,因此所有页面都必须在某处包含令牌值,这可能会使大型网站的实施变得耗时.
  1. 用户成功登录.
  2. 服务器发出身份验证 cookie.
  3. 用户点击以导航到表单.
  4. 页面在浏览器中加载,然后发出 AJAX 请求以检索 CSRF 令牌.
  5. 服务器生成 CSRF 令牌(如果尚未为会话生成),将其存储在用户会话中并将其输出到标题.
  6. 用户提交表单(令牌通过隐藏字段发送).
  7. 服务器检查隐藏字段是否与会话存储的令牌匹配.

优点:

缺点:

  • 如果没有 AJAX 请求来获取标头值就无法工作.
  • 所有表单都必须动态地将值添加到其 HTML 中.
  • 任何 AJAX POST 也必须包含该值.
  • 页面必须首先发出 AJAX 请求以获取 CSRF 令牌,因此每次都意味着额外的往返.
  • 也可以简单地将令牌输出到可以保存额外请求的页面.
  1. 用户成功登录.
  2. 服务器发出身份验证 cookie.
  3. 用户点击以导航到表单.
  4. 如果尚未为此会话生成,服务器会生成 CSRF 令牌,将其存储在用户会话中,并将其输出到页面内容中的某处.
  5. 用户通过 AJAX 提交表单(令牌通过标头发送).
  6. 服务器检查自定义标头是否与会话存储的令牌匹配.

优点:

缺点:

  • 不适用于表单.
  • 所有 AJAX POST 都必须包含标题.
  1. 用户成功登录.
  2. 服务器发出身份验证 cookie.
  3. 用户点击以导航到表单.
  4. 页面在浏览器中加载,然后发出 AJAX 请求以检索 CSRF 令牌.
  5. 服务器生成 CSRF 令牌(如果尚未为会话生成),将其存储在用户会话中并将其输出到标题.
  6. 用户通过 AJAX 提交表单(令牌通过标头发送).
  7. 服务器检查自定义标头是否与会话存储的令牌匹配.

优点:

缺点:

  • 不适用于表单.
  • 所有 AJAX POST 也必须包含该值.
  • 页面必须首先发出 AJAX 请求才能获取 CRSF 令牌,因此每次都意味着额外的往返.
  1. 用户成功登录.
  2. 服务器发出身份验证 cookie.
  3. 用户点击以导航到表单.
  4. 服务器生成 CSRF 令牌,将其存储在用户会话中并将其输出到 cookie.
  5. 用户通过 AJAX 或 HTML 表单提交表单.
  6. 服务器检查自定义标头(或隐藏表单字段)是否与会话存储的令牌匹配.
  7. Cookie 在浏览器中可用,可用于额外的 AJAX 和表单请求,而无需向服务器发出额外请求以检索 CSRF 令牌.

优点:

  • 易于实施.
  • 使用 AJAX.
  • 使用表单.
  • 不一定需要 AJAX 请求来获取 cookie 值.任何 HTTP 请求都可以检索它,并且可以通过 JavaScript 将其附加到所有表单/AJAX 请求中.
  • 一旦检索到 CSRF 令牌,因为它存储在 cookie 中,该值可以重复使用,无需额外请求.

缺点:

  • 所有表单都必须动态地将值添加到其 HTML 中.
  • 任何 AJAX POST 也必须包含该值.
  • cookie 将针对每个请求(即不涉及 CSRF 过程的图像、CSS、JS 等的所有 GET)提交,增加请求大小.
  • Cookie 不能是仅 HTTP.
  • All forms must have the value added to its HTML dynamically.
  • Any AJAX POSTs must also include the value.
  • The cookie will be submitted for every request (i.e. all GETs for images, CSS, JS, etc, that are not involved in the CSRF process) increasing request size.
  • Cookie cannot be HTTP Only.

因此 cookie 方法是相当动态的,它提供了一种简单的方法来检索 cookie 值(任何 HTTP 请求)并使用它(JS 可以自动将值添加到任何表单,它可以在 AJAX 请求中用作标头)或作为表单值).一旦收到会话的 CSRF 令牌,就无需重新生成它,因为使用 CSRF 漏洞的攻击者无法检索此令牌.如果恶意用户试图通过上述任何一种方法读取用户的 CSRF 令牌,那么这将被 同源政策.如果恶意用户尝试检索 CSRF 令牌服务器端(例如,通过 curl),则此令牌将不会与同一用户帐户相关联,因为请求中将缺少受害者的身份验证会话 cookie(它将是攻击者的 - 因此它不会将服务器端与受害者的会话相关联).

So the cookie approach is fairly dynamic offering an easy way to retrieve the cookie value (any HTTP request) and to use it (JS can add the value to any form automatically and it can be employed in AJAX requests either as a header or as a form value). Once the CSRF token has been received for the session, there is no need to regenerate it as an attacker employing a CSRF exploit has no method of retrieving this token. If a malicious user tries to read the user's CSRF token in any of the above methods then this will be prevented by the Same Origin Policy. If a malicious user tries to retrieve the CSRF token server side (e.g. via curl) then this token will not be associated to the same user account as the victim's auth session cookie will be missing from the request (it would be the attacker's - therefore it won't be associated server side with the victim's session).

以及同步器令牌模式 还有双重提交Cookie CSRF预防方法,当然使用cookies来存储一种CSRF令牌.这更容易实现,因为它不需要 CSRF 令牌的任何服务器端状态.使用这种方法时,CSRF 令牌实际上可以是标准的身份验证 cookie,并且该值照常通过 cookie 随请求提交,但该值也在隐藏字段或标头中重复,攻击者无法将其复制为他们首先无法读取值.但是,建议选择另一个 cookie,而不是身份验证 cookie,以便可以通过标记为 HttpOnly 来保护身份验证 cookie.所以这是您使用基于 cookie 的方法发现 CSRF 预防的另一个常见原因.

As well as the Synchronizer Token Pattern there is also the Double Submit Cookie CSRF prevention method, which of course uses cookies to store a type of CSRF token. This is easier to implement as it does not require any server side state for the CSRF token. The CSRF token in fact could be the standard authentication cookie when using this method, and this value is submitted via cookies as usual with the request, but the value is also repeated in either a hidden field or header, of which an attacker cannot replicate as they cannot read the value in the first place. It would be recommended to choose another cookie however, other than the authentication cookie so that the authentication cookie can be secured by being marked HttpOnly. So this is another common reason why you'd find CSRF prevention using a cookie based method.

这篇关于为什么将 CSRF 预防令牌放在 cookie 中很常见?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆