We've recently were handed a security report containing the:

Cookie(s) without HttpOnly flag set

vulnerability, which we apparently had in one of our internal applications.

The applied fix was as simple as setting the Django's CSRF_COOKIE_HTTPONLY configuration parameter to True.

But, this is what got me confused. Django documentation says:

Designating the CSRF cookie as HttpOnly doesn’t offer any practical protection because CSRF is only to protect against cross-domain attacks. If an attacker can read the cookie via JavaScript, they’re already on the same domain as far as the browser knows, so they can do anything they like anyway. (XSS is a much bigger hole than CSRF.)

Although the setting offers little practical benefit, it’s sometimes required by security auditors.

Does this mean that there is no actual vulnerability here and we just have to be complied with the security auditing rules?


As joe says, there is no real security benefit to this. It is pure security theater. I'd like to highlight this from the documentation:

If you enable this and need to send the value of the CSRF token with an AJAX request, your JavaScript must pull the value from a hidden CSRF token form input on the page instead of from the cookie.

The purpose of the HttpOnly flag is to make the value of the cookie unavailable from JavaScript, so that it can not be stolen if there is a XSS vulnerability. But the CSRF-token must somehow be available so it can be double submitted - thats the whole point with it, after all. So Django solves this by including the value in a hidden form field. This negates the whole benefit of HttpOnly, since an attacker can just read the value of the form field instead of the cookie.

  • 11
    To rephrase and summarise your first two sentence slightly, for emphasis: the purpose of the HttpOnly flag is to make the value of the cookie unavailable from your site's JavaScript, but in an Ajax-powered webapp the entire function of a CSRF token relies upon it being available from your site's JavaScript. That's what makes the security report here so wrongheaded. – Mark Amery Dec 15 '17 at 10:29
  • 15
    Additionally, a little experimentation suggests to me that including the CSRF token in a form field is meaningfully less secure than including it in a non-HTTP-only cookie, since if you ever (perhaps accidentally) include an Access-Control-Allow-Origin: * header with a response that includes the CSRF token, it will be readable by attackers if it's included in the response body - but not if it's included in a Set-Cookie header, since reading those in JavaScript is impossible. – Mark Amery Dec 15 '17 at 10:41
  • @MarkAmery Am I missing something? Can't javascript read any cookies which aren't configured with httpOnly? The browser takes the Set-Cookie header and adds it to your cookies as soon as the request completes, and then any JS in the browser can read it (unless httpOnly is set). So it might be true that JS can't read the header itself, but once the header is added to your cookies, it can be read by JS. – colllin Oct 1 at 21:47
  • @colllin JavaScript can read any cookies associated with the domain of the page that the JavaScript is executing on. But in the context of discussing a CSRF attack, we're often imagining a scenario involving an attacker who lures you to a malicious page on a domain the attacker controls which has JavaScript scripts that cause you to submit requests to the site being attacked. The scripts on that malicious page can't read cookies from the victim site, regardless of CORS headers, but may be able to read response bodies if the innocent site's CORS headers are permissive. – Mark Amery Oct 1 at 22:59

That is correct. This is a false positive and the person providing this finding to you does not understand what they are doing unfortunately. Someone that understood the risks of mitm and csrf attacks would never provide this to you.

  • 12
    While this argument is true in this particular case it is recommended to employ strict security settings by default (which includes using httponly) and only have less strict settings if this is really needed by the application and only if one is really sure that loosening security setting does not cause harm in the specific case. In other words: unless there is a reason the CSRF cookie can not be httponly it should be httponly too. Thus, I would actually agree with the security report because not having secure defaults whenever possible is a bad idea. – Steffen Ullrich Dec 15 '17 at 5:05
  • 1
    @SteffenUllrich How could a double submit token work if it is not available from JS? The Django option in question does more than just setting a flag. See my answer. – Anders Dec 15 '17 at 5:22
  • 2
    @Anders: the statement you quote in your nice answer shows a different picture than the question and this answer. And, it does not contradict my comment which said "... unless there is a reason the CSRF cookie can not be httponly it should be httponly too". Obviously in this case there is a reason it should not be httponly and you've showed it in your answer. – Steffen Ullrich Dec 15 '17 at 5:36
  • 3
    @SteffenUllrich While I agree with your sentiment in general, encouraging people to reason about complex security themselves ("unless there is a reason the CSRF cookie can not be httponly it should be httponly too") may be worse than clearly stating "Yeah, CSRF cookies are an exception, you can make them httponly because what they are doing does not need httponly to be secure.". It encourages people to apply reasoning to other areas where the case isn’t as clear and where they might end up with the wrong (insecure) result. – Jonas Schäfer Dec 15 '17 at 8:34
  • @joe yes they would as you pay for a full report and generally that flag is security issue. Unless you say that this is 'out of scope' I would expect that to come back in a report. Don't expect pentesters to understand 100% of the environment you work in or frameworks you choose - its a vulnerability, its up to YOU to figure out the business risk – McMatty Nov 29 '18 at 23:51

While the CSRF-Token is no secret on a page with a CSRF protected form (and could be stolen using XSS), you may have a XSS vulnerability in some page without a form. There you can only get the token from the cookie but not from a hidden field. In this case the security is improved by using a HttpOnly cookie.

There is still a way to get the token by requesting a page which contains a form via javascript. There may be ways to prevent this, but on most sites this attack will be possible.

  • 2
    If there is a XSS vulnerability on a paget without a form I can just request a page with a form and read the token (a little extra work, but not a lot). And if there is an XSS vulnerability, why would I need CSRF anyway? I can just do what I want. – Anders Dec 22 '17 at 14:23
  • That's a point. To your question: CSRF protection is a way to make XSS less dangerous. If you inject some script which tries to submit a POST request, it needs to get the CSRF token from somewhere. As you said, it is quite possible to try to extract it by loading another page which contains a form. – allo Dec 22 '17 at 14:27

Designating the CSRF cookie as HttpOnly doesn’t offer any practical protection because CSRF is only to protect against cross-domain attacks.

This can be stipulated in a much more general way, and in a simpler way by remove the technical aspect of "CSRF cookie".

Designating a cookie as HttpOnly, by definition, only protects against access via document.cookie or equivalent JS methods. It doesn't prevent any HTTP interaction that may have been caused by JS code; any interaction that the user does via HTML elements, like a form submission, can be started by JS. There is no meaningful distinction of how something was started; in fact, you can claim "the user started it" by pointing to the user typing it the URL of the current Webpage, or that of some Webpage that linked to the current Webpage.

That is also the reason why the concept of "autoplay of video" isn't well defined, and cannot be prevented reliably: what constitutes a voluntary user action to start a video is a user interface concept, not a DOM (Document Object Model) concept. The browser doesn't know autoplay from user made a gesture to play a video, unless the video starts before the user makes any move (such as "space to scroll down"). (One can try to "wack a mole" autoplay in a few cases, like one can try to "wack a mole" (detect, black-list) annoying Web ads, or sharing information with third party domains, but without guarantee of coverage.)

Unless JS is completely turned off on a domain, any user action inside the frame controlled by the Website should simply be assumed to be doable by script of the Website. One the modern Web, who turns off JS completely on most domains? Almost no one.

So the generalized observation is:

Designating any cookie as HttpOnly doesn’t offer any practical protection against any against attacks that perform actions that the user might perform through the interface of the Website.

Note that reading all cookies (including those marked HttpOnly) is not done by the interface of the website, it can be done only with the Inspector tool of the browser, or the HTTP proxy for cookies sent over HTTP.


I'm not 100% sure on this so please correct me swiftly if I'm mistaken.

I think the main confusion here is that the Django docs are specifically talking about a CSRF cookie. CSRF is when someone triggers your user's browser to make a request to your server, and their browser automatically sends your server's cookies along with the request. What you don't want is for your server to interpret this request as actually coming from your user, so you use a CSRF mitigation technique.

The whole point of CSRF mitigation is to be able to detect when the request didn't come from your own domain (i.e. from your user interacting with your application).

I think a typical way of handling this is by injecting a randomly-generated one-time string into the page when it is initially returned from the server, and requiring that this string be sent with any requests to the server. Since 3rd parties can trigger your user to send a request to your server, but can't read what is in the response, they are unable to access this random string, and therefore can't include it in the request they force your user to make.

That's why the httpOnly flag is pointless for a CSRF cookie — the crux of CSRF is that they don't need to read your users' cookies, they just need your users' browser to send the cookies to your server. I think the httpOnly flag probably does add value for other cookies, and these cookies are probably what your security audit were referring to. Otherwise, if your CSRF-related cookie is the only one without httpOnly then you should be able to clarify that with them or ignore that point.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.