简体   繁体   English

在客户端设置XSRF cookie

[英]Set the XSRF cookie on the client side

I want to implement a CSRF prevention mechanism for my application by setting a cookie and sending an HTTP header with the same value with every POST / PUT / DELETE request. 我想通过设置cookie并在每个POST / PUT / DELETE请求中发送具有相同值的HTTP标头,为我的应用程序实现CSRF预防机制。 Everywhere I read, the best practices suggest that the csrf cookie should be set from the server. 在我读过的所有地方,最佳实践都建议应从服务器设置csrf cookie。 I'm building a single page app using AngularJS and they also suggest that for security reasons the cookie should be send by the server on the first GET request. 我正在使用AngularJS构建单页应用程序,并且他们还建议出于安全原因,cookie应该由服务器在第一个GET请求上发送。

My question is - why should the server send the cookie and not just set it on the client using simple javascript and a generated random uuid value? 我的问题是-为什么服务器应该发送cookie,而不仅仅是使用简单的javascript和生成的随机uuid值在客户端上进行设置?

Also, if you have a public app that can be accessed by everyone and still need to protect it from csrf, how would the server side remember what token it sends to what user, if they do not have session cookies? 另外,如果您拥有一个可以被所有人访问的公共应用程序,并且仍然需要保护它不受csrf的干扰,那么如果服务器端没有会话cookie,那么服务器端将如何记住它发送给哪些用户的令牌?

why should the server send the cookie... 服务器为什么要发送cookie ...

So that the server can know (authenticate) that the second request from your app came exactly from your app (since that same app is the only receiver of the first request's response). 这样服务器就可以知道(验证)您的应用程序发出的第二个请求完全来自您的应用程序(因为同一应用程序是第一个请求的响应的唯一接收者)。 I say the token is not used for authorization since its derived directly from the user which the token maps to. 我说令牌不用于授权,因为它直接来自令牌映射到的用户。 For example, you can't use the token to delete another user. 例如,您不能使用令牌删除其他用户。 However, your code can still get exploited and that token be compromised to malicious code but let's think about it later on. 但是,您的代码仍然可以被利用,并且该令牌已被恶意代码攻陷,但让我们稍后考虑一下。

...and not just set it on the client... ...而不仅仅是在客户端上设置...

Anything set in advance of communication serves a different purpose, have a look at https://en.wikipedia.org/wiki/Shared_secret or https://en.wikipedia.org/wiki/Symmetric-key_algorithm . 在通信之前进行的任何设置都有不同的用途,请查看https://en.wikipedia.org/wiki/Shared_secrethttps://en.wikipedia.org/wiki/Symmetric-key_algorithm Your app is public which answers why not set it on the client in advance. 您的应用是公开的,可以回答为什么不提前在客户端上进行设置。

using simple javascript and a generated random uuid value? 使用简单的javascript和生成的随机uuid值?

Setting a uuid is pointless because any one can do it: your server can't distinguish between uuid's from your app and hacker's ones. 设置uuid毫无意义,因为任何人都可以做到:您的服务器无法区分应用程序的uuid和黑客的uuid。

Also, if you have a public app that can be accessed by everyone and still need to protect it from csrf... 另外,如果您有一个可以被所有人访问的公共应用程序,但仍然需要保护它免受csrf的侵害...

But if your app (and the API therein) is public you shouldn't protect it, right? 但是,如果您的应用程序(及其中的API)是公开的,则您不应该对其进行保护,对吗? Try curl https://api.github.com/users/mongodb/repos . 尝试curl https://api.github.com/users/mongodb/repos I recently learnt you can disable Bamboo api's XSRF protection by supplying cookie atl.xsrf.token=no-check (also works via header, note that JSESSIONID is still used for the actual authentication). 我最近了解到,可以通过提供cookie atl.xsrf.token=no-check来禁用Bamboo api的XSRF保护(也可以通过标头工作,请注意,JSESSIONID仍用于实际身份验证)。

how would the server side remember what token it sends to what user, if they do not have session cookies? 如果服务器端没有会话cookie,服务器端将如何记住它将发送给哪些用户的令牌?

The XSRF token would normally come in as a custom X- HTTP header. XSRF令牌通常作为自定义X- HTTP标头进入。 Or even as a path/query param, no cookies needed. 甚至作为路径/查询参数,也不需要Cookie。

XSRF is only used to authenticate your app's next request by using a token that your api gave to your app with its last request (or the initial GET where you get new token for free). XSRF仅用于通过使用api随其上次请求提供给您的应用程序的令牌(或用于免费获取新令牌的初始GET来验证应用程序的下一个请求。 As the other answer correctly pointed out, the server can decide to change the token with every idempotent request. 正如另一个答案正确指出的那样,服务器可以决定在每个幂等请求中更改令牌。 Standard practice is to have a new token for every request, they are cheap to generate anyway. 标准做法是为每个请求都有一个新令牌,无论如何生成它们都是很便宜的。

Last but not least, think about some exploit scenarios: 最后但并非最不重要的一点,请考虑一些利用场景:

  • If I manage to inject some javascript and get to your app's cookies where the token is (or dom or js namespace or access your token through some js getter), then I can make authenticated DELETE requests to your api 如果我设法注入一些JavaScript并到达令牌所在的应用程序的Cookie(或dom或js名称空间,或通过某些js getter访问您的令牌),那么我可以向您的api发出经过身份验证的DELETE请求
  • If I manage to redirect your app to my server (any kind of spoofing your DNS, no ssl and so on) and I get to your token, my next DELETE request might get rejected if: 如果我设法将您的应用程序重定向到我的服务器(任何形式的欺骗您的DNS,没有SSL等等),并且获得了您的令牌,则在以下情况下,我的下一个DELETE请求可能会被拒绝:
    • your server expects a new token with every request and... 您的服务器希望每个请求都带有一个新令牌,并且...
    • you managed to be faster than me to make that request in between, I will try again or... 您在两次之间提出要求的速度都比我快,我会再试一次或...
    • the server is smart enough to see that multiple requests with the same token come from different IP's and at least give you a warning like gmail 服务器足够聪明,可以看到具有相同令牌的多个请求来自不同的IP,至少会给您一个类似gmail的警告
  • If I manage to redirect your server api's response (meaning I have a fresh token), my DELETE request will succeed but your next request will give you a warning saying you're access a stale resource (which my request has modified somehow). 如果我设法重定向您的服务器api的响应(意味着我有一个新鲜的令牌),则我的DELETE请求将成功,但是您的下一个请求将向您发出警告,指出您正在访问过时的资源(我的请求已对其进行了某种修改)。 I see that as an optimistic locking over your session. 我认为这是对您的会话的乐观锁定。

In summary, don't use csrf for your public api. 总之,请勿将csrf用于您的公共api。 Use it when you render data, include remote resources in your code or in idempotent calls but then guard it well. 在呈现数据时使用它,在代码或幂等调用中包含远程资源,但要加以妥善保护。 Hope it all makes sense. 希望这一切都有道理。

The whole point of having a CSRF token is so that some malicious user or program won't impersonate another user. 拥有CSRF令牌的全部目的是使某些恶意用户或程序不会冒充其他用户。 Traditionally, a CSRF token is generated by the server and stored in the session for that user. 传统上,CSRF令牌是由服务器生成的,并存储在该用户的会话中。 This will automatically create a cookie for that user and your back-end code should add a hidden form field for the CSRF token to facilitate the form submission. 这将自动为该用户创建一个cookie,您的后端代码应为CSRF令牌添加一个隐藏的表单字段,以方便表单提交。 So whenever a users sends a POST / PUT / DELETE request to your server, you always check if the CRSF token in the server matches with the one submitted by the user. 因此,每当用户向您的服务器发送POST / PUT / DELETE请求时,您始终检查服务器中的CRSF令牌是否与用户提交的令牌匹配。

Also, if you have a public app that can be accessed by everyone and still need to protect it from csrf, how would the server side remember what token it sends to what user, if they do not have session cookies? 另外,如果您拥有一个可以被所有人访问的公共应用程序,并且仍然需要保护它不受csrf的干扰,那么如果服务器端没有会话cookie,那么服务器端将如何记住它发送给哪些用户的令牌?

Well, the server does not really care if the user is authenticated. 好吧,服务器并不真正在乎用户是否通过身份验证。 For any user that visits your site you should create a CSRF token and add it to any form or anything that creates a non-idempotent request to your site. 对于访问您网站的任何用户,您都应该创建一个CSRF令牌并将其添加到任何形式或对您的网站产生非幂等请求的任何内容中。 Adding a CSRF token for a user on the session will just create a cookie and serve it to the browser, this does not require log on. 在会话中为用户添加CSRF令牌只会创建一个cookie并将其提供给浏览器,这不需要登录。 Again, this will make a life of an attacker hard because firstly, they won't have the right cookie to send and second, it's not very like that they will guess the CSRF token that was generated by the user. 再次,这将使攻击者的生活更加艰难,因为首先,他们将没有合适的cookie发送,其次,这与他们猜测用户生成的CSRF令牌的可能性不大。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM