Is it necessary to generate anti-XSRF/CSRF token in server side?

1.5k views Asked by At

Almost all doc about anti-CSRF mechanism states that CSRF token should be generated in server side. However, I'm wondering whether it is necessary.

I want to implement anti-CSRF in these steps:

  1. There is no server-side-generated CSRF token;

  2. In browser side, on every AJAX or form submission, our JavaScript generates a random string as token. This token is written into cookie csrf before actual AJAX or form submission happens; and the token is added to parameter as _csrf.

  3. In server side, each request is supposed to have cookie csrf and submitted argument _csrf. These two values are compared. If they are different, it means it is a CSRF attack.

The server side doesn't need to issue CSRF token, just do the checking; and the token is totally generated in browser side. Of course, this is only for anti-CSRF. There should be authentication process in server side to validate user id.

It sounds a valid solution for CSRF, but I'm not sure why there is no documentation about this approach.

Is there any fault in this anti-CSRF mechanism?

2

There are 2 answers

0
ktalinu On

I suggest to use this approach, I have used on a large scale project:

From: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#use-of-custom-request-headers

Use of Custom Request Headers

Adding CSRF tokens, a double submit cookie and value, an encrypted token, or other defense that involves changing the UI can frequently be complex or otherwise problematic. An alternate defense that is particularly well suited for AJAX or API endpoints is the use of a custom request header. This defense relies on the same-origin policy (SOP) restriction that only JavaScript can be used to add a custom header, and only within its origin. By default, browsers do not allow JavaScript to make cross origin requests with custom headers. If this is the case for your system, you can simply verify the presence of this header and value on all your server side AJAX endpoints in order to protect against CSRF attacks. This approach has the double advantage of usually requiring no UI changes and not introducing any server side state, which is particularly attractive to REST services. You can always add your own custom header and value if that is preferred. This technique obviously works for AJAX calls and you have to still need protect tags with approaches described in this document such as tokens. Also, CORS configuration should also be robust to make this solution work effectively (as custom headers for requests coming from other domains trigger a pre-flight CORS check).

So, instead of sending the token through a request body parameter, you could store and send to the server with a request header parameter.

5
Esteban Cervantes On

As far as I understood, what you want to do is to create your anti-CSRF on the client side, store it in a cookie and also add it as a request parameter, so when the server reads your request, just verifies that your CSRF token cookie and parameter matches, and it decides if it's a valid request or not.

The reason to generate the anti-forgery token on the server side, is that the server will create that token and only the server will know the correct value, so if that parameter is slightly tampered on the client side, it will not be identical to the one stored in the server, and that will be enough to flag the request as a cross site request forgery attack. Any client-side generated data can be tampered by an attacker and because of that, you can't rely on that information, for example, in your approach, you create a random value in your client side and you assign that value to your CSRF cookie and to your _csrf parameter, let's say that your value is "h246drvhd4t2cd98", but since you're only verifying that your 2 variables from the client side have the same value, an attacker can easily just create his CSRF cookie and variable with a value like "I'mByPassingThis" on both of them and your server will flag it as a valid request, so you're not getting security at all. On the other hand, if the token is generated in the server, the attacker has no way to know the expected value, and that value will be different on every request, so the attacker's best approach will be just to try to guess it, which should be virtually impossible, unless you're using a predictable random number generator on the server side.

Also, if you want to create your own anti-forgery token mechanism, you need to take into consideration to use a cryptographically secure pseudo random number generator, but honestly, you should not bother with that, since the current server-generation process is just what you need (assuming that your framework has a built-in mechanism for this, if not, then you still need to make sure that you're using a cryptographically secure pseudo random number generator to generate your anti-forgery tokens).

Remember to never trust user's submitted information. Since it can always can be tampered, you always need to perform a double-check in the server side, and in this case, generating your anti-forgery token in the server is what allows you to double-check to verify the integrity of the submitted anti-forgery token.