为什么将CSRF预防令牌放在Cookie中很常见?
我试图通过CSRF和适当的方式来了解整个问题,以防止它。 (资源我已阅读,理解并同意:OWASP CSRF预防CHGat表,关于CSRF的问题。)
据我所知,围绕CSRF的漏洞是通过假设(从Web服务器的角度来看)传入的HTTP请求中的有效会话cookie反映经过身份验证的用户的愿望来引入的。 但是,所有来源域的cookie都会奇迹般地附加到浏览器的请求中,所以真正的所有服务器都可以从请求中存在的有效会话cookie推断出请求来自具有经过验证的会话的浏览器; 它不能进一步假设在该浏览器中运行的代码的任何内容,或者它是否真的反映了用户的愿望。 防止这种情况的方法是在请求中包含额外的身份验证信息(“CSRF令牌”),该信息通过浏览器的自动cookie处理以外的其他方式进行。 松散地说,会话cookie认证用户/浏览器,并且CSRF令牌认证在浏览器中运行的代码。
因此,简而言之,如果您使用会话Cookie对Web应用程序的用户进行身份验证,则还应该为每个响应添加CSRF令牌,并在每个(变更)请求中要求匹配的CSRF令牌。 然后,CSRF令牌从服务器到浏览器返回服务器,向服务器证明发出请求的页面已被该服务器(由该服务器生成)批准。
关于我的问题,这是关于在该往返中用于CSRF令牌的特定传输方法。
看起来很常见(例如在AngularJS,Django,Rails中)将CSRF令牌从服务器发送到客户端作为cookie(即在Set-Cookie头中),然后让客户端中的Javascript将其从Cookie中除去并附加到它作为单独的XSRF-TOKEN标题发送回服务器。
(另一种方法是Express推荐的方法,其中由服务器生成的CSRF令牌通过服务器端模板扩展包含在响应主体中,直接附加到将提供给服务器的代码/标记,例如作为一种隐藏的表单输入,这个例子是一种更为web 1.0的处理方式,但是会把它推广到更多的JS客户端。)
为什么使用Set-Cookie作为CSRF令牌的下游传输很常见/为什么这是一个好主意? 我想所有这些框架的作者仔细考虑了他们的选择,并没有得到这个错误。 但乍一看,使用cookie来解决cookies本质上的设计限制看起来很愚蠢。 事实上,如果您使用cookie作为往返传输(Set-Cookie:header下游服务器告诉浏览器CSRF令牌,并且Cookie:header上游浏览器将其返回给服务器),则您将重新引入此漏洞正在尝试修复。
我意识到上面的框架不会在CSRF令牌的整个往返过程中使用cookie; 他们在下游使用Set-Cookie,然后在上游使用其他的东西(例如X-CSRF-Token标头),这确实关闭了漏洞。 但即使使用Set-Cookie作为下游交通工具也可能具有误导性和危险性。 浏览器现在将CSRF令牌附加到包括真正的恶意XSRF请求在内的每个请求; 充其量只会让请求变得比它需要的更大,而最坏的情况是一些善意但错误的服务器代码可能会尝试使用它,这将会非常糟糕。 此外,由于CSRF令牌的实际目标收件人是客户端JavaScript,这意味着此cookie不能仅使用http保护。 因此,在Set-Cookie头中向下游发送CSRF令牌对我来说似乎并不理想。
一个很好的理由是,一旦收到CSRF cookie,就可以在客户端脚本的整个应用程序中使用,以便在常规表单和AJAX POST中使用。 这对于AngularJS所使用的大量JavaScript应用程序来说是有意义的(使用AngularJS并不要求应用程序将是单页面应用程序,所以当状态需要在不同的页面请求之间流动时,CSRF值通常不能在浏览器中持续存在)。
在典型应用程序中,考虑您描述的每种方法的一些优缺点以下方案和过程。 这些基于同步器令牌模式。
请求正文方法
优点:
缺点:
自定义HTTP标题(下游)
优点:
缺点:
自定义HTTP标头(上游)
优点:
缺点:
自定义HTTP头(上游和下游)
优点:
缺点:
设置Cookie
优点:
缺点:
所以cookie方法是相当动态的,它提供了一种简单的方法来检索cookie值(任何HTTP请求)并使用它(JS可以自动将值添加到任何表单中,并且可以在AJAX请求中作为标题或作为形式值)。 一旦接收到会话的CSRF令牌,就不需要重新生成它,因为采用CSRF攻击的攻击者没有检索该令牌的方法。 如果恶意用户尝试使用上述任何方法读取用户的CSRF令牌,则相同来源策略将阻止此操作。 如果恶意用户试图检索CSRF令牌服务器端(例如通过curl
),那么这个令牌将不会被关联到同一用户帐户,因为请求中将缺少受害者的auth会话cookie(这将是攻击者的 - 因此它将不会与服务器端与受害者会话相关联)。
除了同步器令牌模式外,还有双重提交Cookie CSRF预防方法,当然它使用cookie来存储一种CSRF令牌。 这更容易实现,因为它不需要CSRF令牌的任何服务器端状态。 CSRF令牌实际上可以是使用此方法时的标准认证cookie,并且该值通常与Cookie一起通过cookie提交,但该值也会在隐藏字段或标头中重复,攻击者无法将其复制为他们无法读取价值。 然而,建议选择另一个cookie,除了身份验证cookie之外,还可以通过标记HttpOnly来确保身份验证cookie的安全。 所以这是你为什么使用基于cookie的方法找到CSRF预防的另一个常见原因。
使用cookie向客户端提供CSRF令牌不允许攻击成功,因为攻击者无法读取cookie的值,因此无法放入服务器端CSRF验证所要求的位置。
攻击者将能够通过请求标头中的身份验证令牌cookie和CSRF cookie向服务器发送请求。 但是服务器并没有将CSRF标记作为请求头中的cookie来查找,而是查看请求的有效载荷。 即使攻击者知道将CSRF令牌放入有效载荷的位置,他们也必须读取它的值才能将其置于那里。 但浏览器的跨域策略会阻止从目标网站读取任何cookie值。
相同的逻辑不适用于auth令牌cookie,因为服务器在请求标头中预期它,并且攻击者不必做任何特殊的事情就可以将它放在那里。
关于答案,我的最佳猜测:考虑如何从服务器获取CSRF令牌到浏览器的3个选项。
我认为第一个请求主体(虽然我在问题中关联了Express教程),但它不适合各种各样的情况; 不是每个人都动态地生成每个HTTP响应; 最终需要将令牌放入生成的响应中的方式可能差异很大(以隐藏的形式输入;在JS代码的片段或其他JS代码可访问的变量中;甚至可能在URL中,尽管这似乎通常是不好的地方放置CSRF令牌)。 因此,尽管可以进行一些定制工作,但#1是一个难以实施一刀切的方法。
第二个是自定义标头,虽然很有吸引力,但实际上并没有工作,因为虽然JS可以为它调用的XHR获取标头,但它无法获取它从其加载的页面的标头。
这留下了第三个,一个由Set-Cookie头部携带的cookie,作为一种易于在所有情况下使用的方法(任何人的服务器都能够设置每个请求的cookie标头,并且不管什么样的数据在请求主体中)。 所以尽管它的缺点,它是框架广泛实施的最简单的方法。
链接地址: http://www.djcxy.com/p/21673.html上一篇: Why is it common to put CSRF prevention tokens in cookies?