我试图理解CSRF的整个问题和适当的方法来防止它。(资料我已经阅读,理解,并同意:OWASP CSRF预防备忘单, 关于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报头发送回服务器。
(另一种方法是例如表达所推荐的方法,其中服务器生成的CSRF令牌通过服务器端模板展开包含在响应体中,直接附加到将其提供给服务器的代码/标记上,例如作为隐藏的表单输入。这个例子是一种更接近web 1.0的做事方式,但可以推广到一个更偏重于js的客户端。)
为什么使用Set-Cookie作为CSRF令牌的下游传输如此普遍/为什么这是一个好主意?我想所有这些框架的作者都仔细考虑了他们的选择,并没有犯这个错误。但乍一看,使用cookie来解决cookie本质上的设计限制似乎很愚蠢。事实上,如果您使用Cookie作为往返传输(Set-Cookie:下游报头用于服务器告诉浏览器CSRF令牌,Cookie:上游报头用于浏览器将其返回给服务器),那么您将重新引入您试图修复的漏洞。
我意识到上面的框架并没有在CSRF令牌的整个往返过程中使用cookie;他们在下游使用Set-Cookie,然后在上游使用其他东西(例如X-CSRF-Token报头),这确实关闭了漏洞。但即使使用Set-Cookie作为下游传输也有潜在的误导和危险;浏览器现在将把CSRF令牌附加到每个请求,包括真正的恶意XSRF请求;在最好的情况下,这会使请求比它需要的更大,在最坏的情况下,一些善意但被误导的服务器代码可能会试图使用它,这将是非常糟糕的。而且,由于CSRF令牌的实际预期接收者是客户端Javascript,这意味着此cookie不能仅使用http进行保护。因此,在Set-Cookie报头中向下游发送CSRF令牌对我来说似乎是次优的。