Why CSRF token cookies don't need to be httpOnly
CSRF token cookies are typically sent without httpOnly set to true. But is that a secure practice?
Security tools will often freak out when they see that your CSRF token is being stored in a cookie without the httpOnly flag set.
But if you set httpOnly, client side scripts won’t have access to the cookie. To make non-GET requests against your back-end, you must send the CSRF token with every such request. This is typically done by injecting a custom header into the request called something like X-CSRFTOKEN when making the request.
Since front-end frameworks like React run entirely on the client, there’s no way to get access to httpOnly cookies. If you use httpOnly for your CSRF token, you won’t be able to perform requests like POST, PATCH, DELETE, etc.
That’s why your CSRF token needs to be in a cookie with httpOnly set to false.
But isn’t this a security problem?
If you don’t set httpOnly, an attacker who injected a piece of Javascript on your page by manipulating the user or his browser will be able to gain access to your CSRF token, and subsequently, perform requests as if they were made by the user himself.
Fortunately, there’s a good measure we can take against such attacks.
Use Content Security Policy (CSP)
CSP was originally designed to handle another class of security exploits known as XSS. It works amazingly for our attack scenario here because while we’re no longer vulnerable to direct CSRF attacks, attackers can steal the token via means of XSS attacks and use it directly.
CSP allows you to specify which origins you trust for your website’s assets. If your website is hosted at mywebsite.dev, you can set it to only allow scripts to be loaded from this specific domain, and not something like anotherwebsite.io.
With this mitigation in place, even if an attacker is able to inject a script tag on your web page, the user’s browser will refuse to load it because it’s not hosted on your domain. Since the script won’t load, the attacker can’t get access to the CSRF token cookie.
All you have to do is set the Content-Security-Policy header to something like default-src ‘self’ on requests originating from the server that your front-end application is hosted at. See more examples here.
As you can see, there’s no reason to freak out about CSRF token cookies not being httpOnly because modern browsers provide us with adequate protection against XSS attacks.
Caveats
While a strong CSP is a critical layer of defense, it is not infallible. Here are some limitations:
- Misconfiguration: CSP can be complex to configure correctly. A policy that is too permissive can be easily bypassed. For instance, including ‘unsafe-inline’ or ‘unsafe-eval’ in the policy significantly weakens its effectiveness.
- Server-Side Vulnerabilities: If a server has a vulnerability that allows an attacker to inject content into a trusted script file, CSP would not prevent that script from executing.
- Bypasses: Clever attackers are constantly finding new ways to bypass CSP directives.
- Other Attack Vectors: CSP primarily focuses on blocking the execution of untrusted scripts. It doesn’t protect against other vulnerabilities like social engineering or other types of injection attacks that might lead to token leakage.
As you can see, setting httpOnly
on the CSRF cookie is the least of your concerns. My advice is if you have high security requirements, craft strict CSP
policies and perform regular audits of your infrastructure.
💡 Need a Developer Who Gets It Done?
If this post helped solve your problem, imagine what we could build together! I'm a full-stack developer with expertise in Python, Django, Typescript, and modern web technologies. I specialize in turning complex ideas into clean, efficient solutions.