我想通过设置cookie并在每个POST / PUT / DELETE请求中发送具有相同值的HTTP标头来为我的应用程序实现CSRF预防机制。我读到的每个地方,最佳实践都建议应该从服务器设置csrf cookie。我正在使用AngularJS构建单页面应用程序,并且他们还建议出于安全原因,cookie应该由服务器在第一个GET请求上发送。
我的问题是 - 为什么服务器应该发送cookie而不是仅仅使用简单的javascript和生成的随机uuid值在客户端上设置它?
此外,如果你有一个可以被所有人访问的公共应用程序,但仍然需要保护它不受csrf的影响,那么服务器端如何记住它发送给哪个用户的令牌,如果他们没有会话cookie?
答案 0 :(得分:2)
服务器为什么要发送cookie ...
这样服务器就可以知道(验证)来自您应用的第二个请求来自您的应用程序(因为该应用程序是第一个请求响应的唯一接收者)。我说令牌不用于授权,因为它直接来自令牌映射到的用户。例如,您无法使用令牌删除其他用户。但是,您的代码仍然可能被利用,并且该令牌会被恶意代码泄露,但我们稍后会考虑它。
......而不仅仅是在客户端设置它......
在通信之前设置的任何内容都有不同的用途,请查看https://en.wikipedia.org/wiki/Shared_secret或https://en.wikipedia.org/wiki/Symmetric-key_algorithm。您的应用是公开的,它可以解答为什么不提前在客户端上设置它。
使用简单的javascript和生成的随机uuid值?
设置一个uuid是没有意义的,因为任何人都可以这样做:你的服务器无法区分你的应用程序和黑客的uuid。
此外,如果您有一个可供所有人访问的公共应用程序,但仍需要保护它免受csrf ...
但是如果您的应用(以及其中的API)是公开的,您不应该保护它,对吧?试试curl https://api.github.com/users/mongodb/repos
。我最近了解到,您可以通过提供cookie atl.xsrf.token=no-check
来禁用Bamboo api的XSRF保护(也可以通过标头工作,请注意JSESSIONID仍然用于实际身份验证)。
如果服务器端没有会话cookie,服务器端将如何记住它向哪个用户发送的令牌?
XSRF令牌通常作为自定义X-
HTTP标头出现。或者甚至作为路径/查询参数,不需要cookie。
XSRF仅用于通过使用您的API为其应用提供的令牌及其最后一个请求(或者您免费获得新令牌的初始GET
)来验证您应用的下一个请求。正如另一个答案正确指出的那样,服务器可以决定用每个幂等请求更改令牌。标准做法是为每个请求设置一个新令牌,无论如何它们都很便宜。
最后但并非最不重要的是,考虑一些漏洞利用场景:
DELETE
请求DELETE
请求可能会被拒绝,如果:
DELETE
请求将成功,但您的下一个请求会给您一个警告,说您访问过时的资源(我的请求已经某种程度上修改)。我认为这是对你的会话的乐观锁定。总之,不要将csrf用于公共API。在渲染数据时使用它,在代码中包含远程资源或在幂等调用中使用它,但是要保护它。希望这一切都有意义。
答案 1 :(得分:0)
拥有CSRF令牌的重点是,某些恶意用户或程序不会冒充其他用户。传统上,CSRF令牌由服务器生成并存储在该用户的会话中。这将自动为该用户创建一个cookie,您的后端代码应该为CSRF令牌添加一个隐藏的表单字段,以方便表单提交。因此,每当用户向您的服务器发送POST / PUT / DELETE请求时,您始终检查服务器中的CRSF令牌是否与用户提交的令牌匹配。
此外,如果您有一个公共应用程序,每个人都可以访问 仍需要保护它免受csrf的影响,服务器端如何记住 如果他们没有会话cookie,它会向哪个用户发送什么标记?
嗯,服务器并不关心用户是否经过身份验证。对于访问您网站的任何用户,您应该创建一个CSRF令牌,并将其添加到任何形式或任何为您的网站创建非幂等请求的内容。在会话中为用户添加CSRF令牌只会创建一个cookie并将其提供给浏览器,这不需要登录。同样,这将使攻击者的生命变得艰难,因为首先,他们将没有正确的cookie发送,其次,他们不会猜测用户生成的CSRF令牌。