1. CSRF . Vulnerability
Easy to find, easy to exploit, can create heavy consequences for users. Depending on where the vulnerability exists, a light user may have some unimportant data edited; If it’s heavy, you can lose money, lose your account, …
To perform a CSRF attack, the hacker will first create a website A pretending to be website B (site B has a CSRF vulnerability), on this site A there is a piece of HTML code. This code will send a request to the server of website B , asking to do something, for example, transfer money to the hacker’s account number. Next, the hacker will use many routes to send a link to site A to the user. If the user opens this link, the HTML code will be triggered to send the request to the server of site B. In case the user is not logged in, even if he does not have an account at site B , it will be fine. But if the user is already logged in to site B , the browser will send the user’s session identifier to site B ‘s server, and the request will be processed. At this time, the money in the user’s account will fly without wings.
Although it is not easy to attack users in reality, but with great consequences if this vulnerability is successfully used, digital service providers are willing to pay large sums of money. appropriate reward for those who discover this vulnerability and report back. Therefore, CSRF is an “easy to play, easy to win” vulnerability for hackers and bounty hunters.
2. How to prevent CSRF
Existing frameworks also support the effective implementation of CSRF protection. Even if developers don’t understand anything about the CSRF vulnerability, they are still guided to implement the precaution through the framework’s documentation. Simply adding a piece of code called CSRF Token to your application, and testing it before executing a user request, can prevent a CSRF attack.
The CSRF snippet is usually added to HTML forms as a hidden value as follows:
1 2 3 4 5 6 7 | <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> form</span> <span class="token attr-name">name</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> change-email-form <span class="token punctuation">"</span></span> <span class="token attr-name">action</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> /my-account/change-email <span class="token punctuation">"</span></span> <span class="token attr-name">method</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> POST <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> label</span> <span class="token punctuation">></span></span> Email <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> label</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> input</span> <span class="token attr-name">required</span> <span class="token attr-name">type</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> email <span class="token punctuation">"</span></span> <span class="token attr-name">name</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> email <span class="token punctuation">"</span></span> <span class="token attr-name">value</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> example@normal-website.com <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> input</span> <span class="token attr-name">required</span> <span class="token attr-name">type</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> hidden <span class="token punctuation">"</span></span> <span class="token attr-name">name</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> csrf <span class="token punctuation">"</span></span> <span class="token attr-name">value</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> 50FaWgdOhi9M9wyna8taR1k3ODOR8d6u <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> button</span> <span class="token attr-name">class</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">'</span> button <span class="token punctuation">'</span></span> <span class="token attr-name">type</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">'</span> submit <span class="token punctuation">'</span></span> <span class="token punctuation">></span></span> Update email <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> button</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> form</span> <span class="token punctuation">></span></span> |
The outgoing request from the browser will look like this:
1 2 3 4 5 6 7 | <span class="token request-line"><span class="token method property">POST</span> <span class="token request-target url">/my-account/change-email</span> <span class="token http-version property">HTTP/1.1</span></span> <span class="token header-name keyword">Host:</span> normal-website.com <span class="token header-name keyword">Content-Length:</span> 70 <span class="token header-name keyword">Content-Type:</span> application/x-www-form-urlencoded csrf=50FaWgdOhi9M9wyna8taR1k3ODOR8d6u&email=example@normal-website.com |
But maybe because it is not clear how the CSRF Token works, nor about the CSRF attack, the implementation of CSRF prevention in some cases is not really effective. At this time, hackers can still bypass the CSRF Token authentication process to exploit this vulnerability.
Next, let’s find out some cases where hackers can pass CSRF Token authentication, in the following cases there is no case like you, let’s fix it.
3. Some cases pass CSRF Token authentication
3.1. CSRF Token validation is done based on HTTP
In some cases, CSRF Token validation was done very well on some HTTP methods, but in others it did not perform authentication or did not have CSRF Token at all. For example, all requests sent via the POST method are attached to the CSRF Token, when the packet arrives at the server, it must also undergo CSRF Token authentication before making the request. But with the GET method, that is not the case.
Maybe because the project was originally designed to only send requests that can change data via the POST method, and the GET method will only be used to request reading data from the server. In case the entire source code is implemented according to this design, there will be no CSRF vulnerability, because all requests that need to use the POST method are already correctly authenticated with the CSRF Token.
But it is possible that during application development, the programmer has unintentionally made data changes to a request using a certain GET method. Or the project did very well, but later when developing more functions, the team of programmers had new people who did not understand the unified requirements from the beginning. This leads them to actively create data editing requests via the GET method, and also forget about validating the CSRF Token with the GET method. This will create a CSRF vulnerability.
Therefore, to minimize this possibility, we should check all data change requests from the user. Ensure that any request to change data from the user, regardless of the method, requires full CSRF Token validation . At the same time, it is also possible to strictly comply with application design regulations, for example , when using RESTful API, it is necessary to authenticate on every request via POST, PUT, DELETE methods; also do not make data changes when the request is sent via GET method.
3.2. CSRF Token is not tied to the user’s session
This is the case that can happen when the programmer has properly complied with the CSRF Token authentication, but does not pay attention to the association between the CSRF Token and the user’s session. The reason that only a CSRF Token can prevent a CSRF attack is because the hacker doesn’t know the token, so it is not possible to attach the token to the HTML code sent to the user. So if the hacker can know what the content of the CSRF Token is to be able to pass the authentication, then the hacker can perform a CSRF attack.
If the application only generates a series of CSRF Tokens and doesn’t care which account this token belongs to, as long as the CSRF Token attached in the request from the user matches the CSRF Token generated by the application, the hacker can bypass through authentication easily. Just create an account on that website, get the CSRF Token from your account and attach it with the HTML code to execute the attack. When the user opens the link, the executed HTML code sends a request to the server under their session identifier and the hacker’s CSRF Token. The server checks that the session is valid, the CSRF Token is valid, and it will change the data without paying attention to whether the token is the correct account or not.
Therefore, it is necessary to check whether the user’s session and the CSRF Token are bound to each other? When it comes to checking which account a CSRF Token belongs to, the hacker cannot bypass the authentication using another account’s valid CSRF Token.
3.3. The CSRF Token is bound to the cookie, but not the user’s session identifier
This case is similar to case 3.2. In this case, the CSRF Token is bound to a cookie, but the cookie is not the user’s session identifier. This can happen when the application uses two different frameworks/libraries: one for session identifier management and the other for CSRF Token management. Since these two components do not work together, the CSRF Token cannot be easily bound to the session identifier. If you want, you have to code it yourself.
In this case, the CSRF Token will be bound to a certain cookie (temporarily called the CSRF_Key cookie). The CSRF_Key cookie will be issued and saved in the user’s browser after successful login. And the CSRF_Key cookie of different accounts will be different. Therefore, account A’s CSRF Token cannot be used for account B. When the server checks that the CSRF_Key cookie belongs to account A but the CSRF Token belongs to account B, it will not make the request.
It’s safe to say it’s safe, but it’s not absolute. If the application has a vulnerability that allows a hacker to set a value for the user’s cookie, then the user’s CSRF_Key cookie can be modified by the hacker into the hacker’s CSRF_Key cookie. Then the hacker only needs to perform a CSRF attack with the hacker’s CSRF Token.
In the end it is still more secure to bind the CSRF Token to the session identifier. Because even if the hacker can incorporate another vulnerability to change the session identifier stored in the cookie, what does it mean? If the session identifier changes, the account is no longer the same account. If the binding CSRF Token along with the user’s session identifier cannot be found, a CSRF attack is not possible.
3.4. Fixed CSRF Token
Ever heard of the case where the session identifier is fixed with every login? Yes, there is a case where this happens in that reality. And there are also cases where CSRF Token is fixed. Usually this is the case when CSRF Token generation and validation is self-developed. If we compare the danger and the possibility of being exploited, this case is safer than the previous 3 cases. But if the user, through a certain way, exposes the CSRF Token, then the safety is no longer available. Two simple scenarios can be thought of leading to the disclosure of CSRF Token:
- The CSRF Token is stored in a cookie, and the site is vulnerable to XSS. The session identifier stored in the cookie has been flagged HttpOnly and Secure for protection, but the CSRF Token is not. At this time, the hacker can exploit the XSS vulnerability to get the user’s CSRF Token.
- CSRF Token is fixed and generated by predictable factors. For example, generated by Base64 encoding easy-to-guess elements such as usernames,…
In general, the fixation of CSRF Token is not secure enough. CSRF Token should be generated continuously, and each CSRF Token will have a certain validity period. When the time limit is over, the CSRF Token will be rejected and the request will not be processed.
Above are some cases where CSRF Token implementation is not secure enough, leading to hackers being able to bypass the authentication process to perform CSRF attacks. Do you have any questions about CSRF Token? Please leave a comment below if you have one.
The article is referenced from the following sources: