Why do we need CSRF tokens?

Dr. Adam Nielsen
3 min readOct 17, 2022

--

What are CSRF tokens?

CSRF stands for Cross-Site-Request-Forgery.

A CSRF token is a token stored in your session. Every FORM that you open on your website will include this token in the form as a hidden input field. When a user makes a POST request, one can validate the CSRF token from the FORM with the token in the session.

This makes sure that the user who is logged in on your site, actually submitted the FORM on your site (and not from a mail or so). But did you hear ever from the same origin policy? If so, you may wonder why CSRF tokens are even needed..

What is same origin policy?

All browsers implement the same-origin policy. This policy avoids in general that a web application on domain A can make an HTTP request to an application on domain B. This is in general a good thing because we don’t want malicious-neighbar.com to attack our website.

However, it does not restrict all requests. For example, same-origin policy does not restrict embed tags like this:

<img src="https://dashboard.example.com/post-message/hello">

You may be embedding a youtube video or an image from outside of your website. This exception is the reason it worked, despite the same-origin policy.

It’s irrelevant whether the response is a valid image — the request is still executed. This is why it’s essential that state-changing endpoints on your web application cannot be invoked with the GET method.

How can websites interact with different domains?

You may use CORS to avoid same-origin policy and let domain A make a request to domain B that would otherwise be forbidden. Before the actual request is sent, a preflight request will be sent to check if the server allows domain A to send this request type. If it does, domain A will send the original request.

For example, if no CORS is set, then a Javascript XMLHttpRequests would be restricted for domain A by a preflight, without executing the request on domain B.

Why you need CSRF token despite same-origin policy

If same-origin policy would work for all types of request then you would be right and there is no need to use CSRF token, because you would have full protection by the same-origin policy. However, this is not the case. There are a couple of HTTP requests that do not send a preflight request!

GET, HEAD and POST requests with specific headers and specific content-type do not send a preflight request. Such requests are called simple requests. This means the request will be executed and if the request was not allowed, then a not-allowed error response will be returned. But the problem is, that the simple request was executed on the server.

Unfortunately, a plain <form action="POST"> creates a simple requests!

And because of these simple requests, we have to protect the POST routes with CSRF tokens (GET routes don’t need CSRF because they can be read anyway by embedded tags as shown above. Just make sure you don’t have a state-changing get method).

Can we not just check the origin header?

The header contains an origin field that is not changeable via javascript. However, it can be changed when you make a request outside the browser, for example, a curl request from the terminal. Therefore, we need CSRF token for our form posts.

--

--

Dr. Adam Nielsen
Dr. Adam Nielsen

Written by Dr. Adam Nielsen

PHD in math. and Laravel / Vue Full-Stack-Developer

No responses yet