Preventing Cross-Site Request Forgery using Double-Submit Cookie Pattern

This blog post will discuss Double-Submit Cookie Pattern also known as Stateless CSRF Defense, for preventing Cross-Site Request Forgery. If you are unaware what CSRF is and how they happen, you may refer this post.
As discussed previously Synchronizer Token pattern, the server will store the CSRF tokens against the session IDs. This introduces a concern as sessions cost memory and may result in imbalances in terms of load distribution across web servers. With a significant amount of users consuming the system at a given time, the memory used will also grow exponentially. This is when Double Submit Cookie pattern comes to play. In Double Submit Cookie Pattern, the server will not store the tokens, hence called Stateless CSRF Defense.

How does it work?
When a user logs into the site, a session is created and the session ID is set as a cookie in the browser. At the same time, another cookie is set for the CSRF token.
Next, when the user submits a secure form, this token is extracted from the cookie and is set as a hidden input field in the HTML. This cookie cannot be set as HttpOnly as the clientside script requires to access this because in this scenario, the token endpoint does not exist and the server has no record of the generated token for this session.
The server will validate the token sent as a form parameter against the cookie value and authorize the action to be completed. A cross-origin attacker cannot read any data sent from the server or modify cookie values, per the same-origin policy.
Let’s look at how we can implement this
Here, in the login, when the user is successfully authenticated it will generate a session cookie and CSRF token cookie.
You can observe the cookies in your browser as below.

The CSRF token is set as a cookie and sent unlike in the Synchronizer pattern because this value is not persisted in the server. But cookies cannot be manipulated by any third party. A client-side script will retrieve this value and inject it to a hidden field on the form loading to be submitted along with the form.
var csrf = document.cookie.replace(/(?:(?:^|.*;\s*)Csrf-token\s*\=\s*([^;]*).*$)|^.*$/, "$1");
$("#submit-btn").before('<input type="hidden" name="csrf" value="'+csrf+'">');When a request is received for the /transfer endpoint, it will authenticate the session and the CSRF. Below are the controller and the service.
The controller calls the isAuthenticated method that checks whether the session and the token are valid.
The service has the implements the isAuthenticated method as below.
If we submit the form without the hidden field value, it will fail as below.


Even if an attacker forges this request, since the CSRF token set as the cookie is invisible to the attacker, so will fail to send the same token along with the other form parameters.
Full implementation of this sample app can be found at https://github.com/dinuish94/double-submit-cookie-pattern.
So is our application CSRF-proof now?
Not really. There are still some security consequences:
- Cookies cannot be tagged as HTTPONLY
- Potential XSS vulnerabilities in subdomains can introduce poisoned cookies in upper domains
- Man in the middle attacks
Cookies with sensitive server metadata should contain the HTTPOnly flag. But in this case, we cannot facilitate that, hence it introduces a potential security concern.
Also, if this pattern is implemented, we have to make sure the application is fully XSS-resistant if the application is in a subdomain.
You can read more about these vulnerabilities here.
