Codeigniter CSRF - penetration test - codeigniter

I am using codeigniter 3.1.9.
I have enabled my CSRF protection with csrg_regenerate set to true. It works fine, the token regenerates every time on Post request, validation works as well. On top of that, I have also set my cookie to same-site strict connection only.
I then submitted for penetration test assessment to the security team, they rejected my work because of csrf attacks vulnerability.
The argument was, they changed the cookie token and post params, then perform the attacks.
Here is the proof:
Their response : CSRF token is not securely implemented. An attacker can still perform a CSRF attack using any value to the csrf_cookie_name Cookie and csrf_test_name parameter.
How can I solve this ?
Thanks

Its the first time to see a security token stored in cookies on the client side that's why of course your system is vulnerable.
You must store the token in your session that makes them impossible to retrieve.
The way to implement it:
Create a hidden input in your form with the csrf token and on form submit compare it with your token that is stored in the session.

Related

What is the point of X-CSRF-TOKEN or X-XSRF-TOKEN, why not just use a strict same site cookie?

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.

How are CSRF tokens stored on the server side ( by spring security or tomcat)

This question is not about how CSRF tokens works, but is rather about they are stored on the server side.
In short, CSRF tokens are generated by server and injected in to the web page/form. When the form is submitted the csrf token is extracted by the server and compared to the one saved on the server. So far so good.
From this earlier posting - CSRF token value when same page is opened in two tabs on same machine?
Here's the excellent answer which explains that -
The server will create a CSRF token (token1) and store that token in
the HttpSession. The CSRF token (token1) is also be embedded in the
form on the client side. The client is also given a Session ID
(session-id1) which is stored in a cookie.
When the client submits the form, it sends token1 and session-id1. The
server will then use session-id1 to look up the HttpSession and get
the expected CSRF token for that session. It will compare the expected
CSRF token to token1 and if the values do not match, the HTTP request
will be rejected.
and
If you open the same form in another tab, the browser will still have
access to the Session ID (session-id1). That form will get the same
token (token1) that was associated with session-id1.
In the end, there is only one CSRF token (token1) that is used in both
tabs.
Bit more info can be found in the quoted reference, but it fails to explain the server side part.
The above leads to more questions -
If another form (form2) is opened by user in a different tab - then what CSRF token will it get, will it be same as that for the first form(form1) ?
To explore and unsderstand better, I want to know where and how the CSRF tokens are stored in the backend when using spring security (unlike Session Cookies which are generated by Servlet Container, I am assuming that CSRF tokens are generated by Spring Security module). Is there just one CSRF token per session, which is used accross every form and every tab or there are several CSRF tokens.
Please clarify as much as you can... every drop counts

CSRF token value when same page is opened in two tabs on same machine?

From my understanding, when CSRF is enabled on server side, the server creates a token (say token1) and injects it in to the form and saves the same in the cookie of the client browser.
When the client sends the form request to the server, it sends the csrf token (token1) from browser cookie and also send the same token as in the form. The server validates the request by checking that the token in cookie and the token in form match and then processes the request.
Now, if i open the same form in another tab, will the server generate another token (token2) and inject it in to the form and cookie. Then, in the cookie, token1 will be overwritten by token2. So the submission of the form in first tab will not work in this case? But from experience i see that the submission of form in tab 1 still succeeds.
So can some one explain how it's succeeding in the above scenario??
Since you have added the Spring Security tag, I will describe how Spring Security uses the Synchronizer Token Pattern to protect against CSRF attacks.
the server creates a token (say token1) and injects it in to the form and saves the same in the cookie of the client browser.
That's not exactly what happens. The server will create a CSRF token (token1) and store that token in the HttpSession. The CSRF token (token1) is also be embedded in the form on the client side. The client is also given a Session ID (session-id1) which is stored in a cookie.
When the client submits the form, it sends token1 and session-id1. The server will then use session-id1 to look up the HttpSession and get the expected CSRF token for that session. It will compare the expected CSRF token to token1 and if the values do not match, the HTTP request will be rejected.
If you open the same form in another tab, the browser will still have access to the Session ID (session-id1). That form will get the same token (token1) that was associated with session-id1.
In the end, there is only one CSRF token (token1) that is used in both tabs.
You can find more information about protection against CSRF attacks in the Spring Security reference documentation.

Regarding Cross site Scripting Forgery

I am working on csrf and using spring 5. Spring 5 automatically provide supports for csrf and on enabling csrf protection on the server side I am getting
403: Invalid X-CSRF token
So this means a token needs to come from frontend?
My understanding is that backend generates csrf token and sends as a response to frontend browser and then it uses this token and send it as cookies to the backend server and then backend will validate it. is my understanding is correct?
when manually generating the hidden token for csrf, How backend will know it is a valid csrf token?
Second Scenario: Suppose two users are logged in to my website and frontend is sending this token to backend then how the application will differentiate which token is for which user?
Also please explain how it works internally means we enabled csrf protection in the backend and manually generated a token on the front end then what it does behind the scenes?
consider my frontend is JS pages
Is there is any specialty of Spring 5 which take care's of sessions for each user and validate tokens automagically for each user?. I tried finding it on the official website but didn't get it anywhere
Hi Zaib the csrf token is generated from back-end as you stated, once it is generated is automatically sent to the front-end which must take care to retrieve from the model and re-post for each "POST" requests.
You can share the csrf token via different way mostly i used header or html parameter.
A token is related to a specific session so is not really important if you have a logged user or not , even not authenticated users must send the csrf token for "POST".
The csrf token is validated via a filter placed in the front of the filter chain defined by Spring security itself, if you search in the documentation there is a table showing you the position of each "default" filter enabled by Spring security. Moreover if you enable debug on Spring ( </debug> is enough in your xml configuration) you will have printed all the filters used while processing an http request.
So each time a request with "POST" method pass through that filter , it will check if in the parameters there is the csrf token or header.
I never used as cookie so it may a different case for you if specifically need that but it does not differ on how it works.
Here is the details of csrf implementation on Spring:
https://docs.spring.io/spring-security/site/docs/5.0.7.RELEASE/reference/htmlsingle/#csrf-configure
I said "POST" method but actually the token is checked for any method that is related to a change of state , you can refer to doc here:
https://docs.spring.io/spring-security/site/docs/4.2.5.RELEASE/apidocs/org/springframework/security/web/csrf/CsrfFilter.html
Hope this help clarifying a bit the usage of the csrf token.

Why can't a malicious site obtain a CSRF token via GET before attacking?

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.

Resources