Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django won't set HttpOnly for csrftoken cookie

In my Django's settings.py I have

SESSION_COOKIE_HTTPONLY = True
SECURE_CONTENT_TYPE_NOSNIFF = True
SECURE_BROWSER_XSS_FILTER = True
X_FRAME_OPTIONS = 'DENY'
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_SSL_REDIRECT = True
SECURE_HSTS_SECONDS = 15768000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
SESSION_COOKIE_AGE = 2 * 24 * 3600

However https://detectify.com has found that this flag isn't set for csrftoken cookie. I checked what Chrome tells about the cookie, and if I understand correctly, the empty HTTP column confirms that the two cookies are not HTTP-only: enter image description here

Also, if I do document.cookie in chrome's console, the csrftoken value is shown.

I wonder why this could be the case. I have Django running on uwsgi and nginx. The nginx configuration is as follows, and the site in question is https://rodichi.net:

server {
    listen 443 ssl http2 default_server;
    server_name rodichi.net;

    ssl_certificate /etc/letsencrypt/live/rodichi.net/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/rodichi.net/privkey.pem;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
    ssl_protocols TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
    ssl_ecdh_curve secp384r1;
    ssl_session_cache shared:SSL:10m;
    ssl_session_tickets off;
    ssl_stapling on;
    ssl_stapling_verify on;
    charset     utf-8;

    ... # location settings follow here

```

like image 217
texnic Avatar asked Jun 30 '17 15:06

texnic


Video Answer


1 Answers

You have only configured it to have the CSRF token be set to Secure (i.e. only sent over https requests) and not to be HttpOnly (i.e. not available to Javascript).

Looking at the Django documentation you also need to set CSRF_COOKIE_HTTPONLY. However the documentation rightly points out:

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.

It also depends how you have implemented CSRF. There are basically two methods for forms:

  1. Set a hidden CSRF field for each form and make this field generate a unique value each time the form is loaded. Therefore if the form submission includes a valid code, then you know the request came from your domain. This is complicated on the server side, as it requires keeping track of valid tokens and also means each form must be dynamically generated to include a random token, but is easier on client side as uses standard form requests rather than JavaScript. For this protection the CSRF cookie is not needed and is not used even if it is present.

  2. The other method invokes setting a CSRF cookie, and having the Javascript read this and send it in a HTTP header (usually X-CSRF-TOKEN). A CSRF request from another domain won't have access to this CSRF cookie so won't be able to set the header correctly. As the cookies will be also be sent on all requests it's easy for the server to check the cookie in the HTTP Request matches the header set in the request. Which means the request came from a somewhere that has access to the cookies, which means it came from same domain. Which means it's not a CSRF attack. This is easier to implement on the server side (as no need to keep a list of active Tokens) but requires Javascript at the front end and requires a CSRF token not to be HttpOnly - precisely because the Token is supposed to be read by Client side Javascript!

Again the Django documentation warns against this:

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.

So, all in all, it is not recommended to set the HttpOnly attribute for this cookie. It limits you, adds no real protection, and makes the cookie itself meaningless.

You will get it highlighted in and Pen Test reports on your site (including https://detectify.com by the looks of things) but should accept that as you are comfortable that this is correct. Not sure if it's possible to whitelist this cookie in https://detectify.com so it doesn't alert each time?

like image 152
Barry Pollard Avatar answered Nov 15 '22 09:11

Barry Pollard