I'm trying to better understand the mechanism for how Spring CSRF protection works. Suppose I have a site https://example.com/ where people can vote on candidates. Users can also exchange messages. I also have a user logged in, and another user that sends her a message saying to click on the link https://example.com/vote/candiate/30.
If a user clicks on this link, won't the browser send both the CSRF token and the session ID for the logged in user, thereby bypassing the CSRF protection check?
The reason a link is usually not a problem regarding CSRF is that CSRF is only an issue when the request changes something. A link (a GET request) should not change anything. If it does, like in your example it adds a vote to the candidate I suppose, any link from an external origin (a different website) would also be able to exploit "normal" CSRF by just linking to that url.
The problem in the example is not that CSRF protection is inadequate in Spring, the problem is that voting in this case is a GET request, and GETs are not usually protected against CSRF by design. The solution is to change the vote request to a POST, which would then be protected against CSRF (and which would also be more RESTful btw).
Main idea :
When request is submitted, the server received special cookie and waits for defined value in this cookie. If this value will be differet , the request should fail.
So, if service returns form for moving money between accounts, this form includes parameter, that expected to receive when form is submitted, and if data would be sent without this parameter, request wouldn't be proccessed
Related
Frameworks such as laravel and others require you place the csrf token in your HTML forms.
However at the same time laravel comes by default with the VerifyCsrfToken middleware that automatically creates a X-XSRF-TOKEN cookie with the csrf token on every response. This cookie is used for ajax requests and is automatically added to the header for axios for example.
I am wondering why is it required to add the csrf token to every HTML form. Why could you not just use the already existing X-XSRF-TOKEN cookie to validate the csrf token. I understand there is the issue of same site cookies, and if your csrf cookie is set to lax or none the cookie would be sent from an external site if they would POST to my site. However this issue can be solved by setting the same site to strict then there would be no need to set the csrf token on every form which is kind of annoying to do and remember.
Is there some security concern I am missing on why we just cant use a strict cookie for validating the csrf token?
An X-CSRF-Token protects users against unwanted execution of modifying requests, which are of interest for their side effects (the changes which they make to the server, or the database), not for their response, which the attacker cannot read anyway, by virtue of the CORS protocol.
A same site cookie would protect even against execution of navigation requests, which do not change anything on the server, but only read data (including X-CSRF-Tokens for subsequent modifying requests), which is then displayed in an HTML page. For example, if stackoverflow.com had same site session cookies, you would not be able to navigate from your webmail site via a mailed link to this StackOverflow question and immediately click to upvote it, because the session cookie would not be included in the navigation request, therefore you would not be logged on at first.
SameSite cookies do indeed provide significant protection against CSRF attacks.
But it's always better to put an explicit counter-measure in place - that is provided by anti-CSRF tokens.
For one thing, SameSite uses a notion of "registerable domain" so it does not protect you against subdomain hijacking
Finally, for these topics I very much recommend an excellent book Api Security in Action - they discuss CSRF and related topics in Chapter 4.
there would be no point in validating csrf token through cookies. That's the problem we are trying to solve. If csrf token was sent and validated as a cookie, it also could be sent, and is sent in cross site request. But when doing cross site request, as far as I know, attacker can't read that cookie with js and put it inside the form, only we can access that cookie with js. That's because when we set a cookie we specify domain attribute, and that cookie can be read with js, only on that particular domain. That's the reason why that cookie is not http only, and why we include it inside forms.
Using CSRF token in rest API is helpful or not ? as far as I know we don't have a session so we should send the token to client for next request or for submitting the form.
Is it helpful to use it again in ajax(xhr) calls. are there any alternatives ?
I've been reading the spring documents for this, and it also has some examples. but I was curious that is it really helpful or not ?
By the way My server is spring 2.2 and my client is Angular 9.
Thanks
CSRF tokens are essential for preventing XSS attacks, for instance you are logged into your bank, in one tab, and visiting my malicious site that will send a hidden form to your bank stealing your credicard number.
If you want to build a more secure site, every request that manipulates the state in the backend (POST, PUT, DELETE etc) should have a CSRF token included, to ensure that the request came from forms on your site and only your site.
You can read more about CSRF tokens on Owasps webpage.
If I understand correctly, in a CSRF attack a malicious website A tells my browser to send a request to site B. My browser will automatically include my B cookies in that request. Although A cannot see those cookies, if I'm already authenticated in B the request will look legit, and whatever action was asked will be successfully performed. To avoid this, every time that I visit a page of B containing a form, I receive a CSRF token. This token is associated to my session, so if I make a POST to B I MUST include such token; otherwise B rejects my request. The benefit of this scheme is that A will not have access to that token.
I have two questions:
Is the above description correct?
If so, why can't site A first tell my browser to send a GET to B, obtain the CSRF token from the response, and then use the token to send now a POST to B? Notice that the token will be valid and associated to my session, as the GET also contains all my B cookies.
Thanks!
Your description is correct.
If site A tells your browser to go to B and get the token, that's fine, but as it is a cross-domain request, A will not have access to the token in Javascript (this is a browser feature). So when A tells your browser to go back to B and actually do something, it still cannot include the token in the request.
That is, unless B set the token as a cookie. Evidently, that would be flawed, because the token cookie would also be sent, thus negating any protection. So the token in this case must be sent as either a form value or a request header (or something else that is not sent automatically like a cookie).
This also means that if B is vulnerable to cross-site scripting, it is also vulnerable to CSRF, because the token can then be stolen, but CSRF is the smaller problem then. :)
Correct.
Site A can't get site B's csrf token because of the browser's CORS strategy.
And we need to validate the request's referer(It can be forged).
https://en.wikipedia.org/wiki/HTTP_referer
It is also a good practice to validate the crsf token in url(AKA query string).
FYI,Laravel, a popular web framework, uses a hidden CSRF token field in the form to prevent csrf attack.
I know that to protect web applications from Cross Site Request Forgery, the only secure method is implementing a CSRF token. My question is, isn't it possible to use the CSRF token to track sessions also? Why should we implement a different session id to track the sessions?
A CSRF token is a value that must be generated randomly and associated to a session (a user) in EVERY GET that shows a form to prevent false POST. This false POST comes from the user browser too so, to authenticate the POST, you need a session with the token stored in server memory to compare if the token that comes with the POST is the same that is stored in user session.
Also, web app's shuold need to identify users in a GET and CSRF tokens are only in POST.
Session need to be static to identify user along time and several request due to disconnected nature of HTTP. CSRF changes in every GET, it can not be used like session.
In the other hand. What server should do with your idea? Create a new session every GET and copy all previous session data to the new session? This is crazy.
Take a look to this pdf at Montana State University. It helps me to understand CSRF.
I'm using Symfony2 and protecting my forms with a CSRF token.
I have a comments system based on Ajax calls. If a user wants to edit his comment, here's what's happening:
A user hits the edit button.
A "fresh" comment edit form is loaded via ajax.
The user edit and submit the form via ajax.
The edited comment is sent back in response.
Is loading the "fresh" edit form via ajax a security risk?
If the form were already in the loaded page and couldn't be requested via ajax, an attacker could not guess the CSRF Token, but since he can request the form he can get his hands on the Token..
Couldn't he..?
Maybe an example will make it clearer:
Dave is an innocent registered user in my site (www.acme.com).
Dave logged in my site and then visited www.evil.com. He doesn't know that, but when he visited evil.com a script was executed.
The script sent an ajax request to www.acme.com/comments/123/edit and got the edit form in response.
It then filled in that form with it's malicious content and submitted that form (again, with ajax).
Will evil's evil plan work?
As far as i understand, there is no risk if your form contains CSRF token field. Default Symfony2 CSRF token depends on session which is not availiable for the attacker (and also on intention). So when the attacker requests the form there is attacker's (not user's) session id used.