Tip: making SSL-only websites
Feb. 6, 2015
When deploying websites, adding SSL should in my opinion be a standard practise. This for a few reasons:
- Protecting the privacy of your users.
- Protecting your visitors when they use Wifi-hotspots
- Protecting your admin interface against session-cookie-theft.
- Making life harder for government agencies to read traffic.
There are a few things to do to implement SSL (actually TLS) property
1. Django configuration
When a site is accessable over HTTPS only, the following settings give maximum security:
# For https only sites: CSRF_COOKIE_SECURE = True SESSION_COOKIE_SECURE = True # Improve cookie protection SESSION_COOKIE_HTTPONLY = True # can't read cookie from JavaScript, default in modern Django SESSION_EXPIRE_AT_BROWSER_CLOSE = True # Enable clickjacking protection # Can be overwritten per view using the @xframe_options_.. decorators X_FRAME_OPTIONS = 'DENY' # Prevent iframes, alt: SAMEORIGIN. MIDDLEWARE_CLASSES = ( # ... 'django.middleware.clickjacking.XFrameOptionsMiddleware', # ... )
The first two fields avoid exposing the cookie over HTTP, which could give attackers an opportunity to read the cookie. When a hacker is able to read the session-cookie, they can impersonate themselves as your account, and log into your site. This is obviously a security risk.
The remaining settings are optional, but give better security. A clickjacking site for instance, tries show your site in an iframe, and overlay an element to catch user input.
2. Nginx configuration
Just adding SSL settings to Nginx is not enough. To get an A+ score in the SSL test you need to configure the SSL ciphers properly. There are various combinations, this is an example:
ssl_ciphers "ECDH+AESGCM ECDH+AES256 DH+AESGCM DH+AES256 ECDH+AES128 DH+AES ECDH+3DES DH+3DES RSA+AES RSA+3DES !RC4 !ADH !AECDH !MD5 !DSS"; ssl_prefer_server_ciphers on; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; # Diffie-Hellman parameter for DHE ciphersuites, recommended at least 2048 bits ssl_dhparam /etc/ssl/private/dhparam.pem; # Enforce strict policies in browsers, and be SSL-only add_header Strict-Transport-Security "max-age=31536000"; # optional: ; includeSubdomains add_header X-Content-Type-Options nosniff;
This combination ensures that:
- Browsers get the best possible encryption by default
- ECDH ciphers are preferred, which give Perfect Forward Secrecy.
- SSL v3 and RC4 are disabled, which is really insecure.
Please verify these cipher settings against the current SSL test suite, it’s possible you may need other ciphers in the future. The dhparam file is needed to give a higher key exchange for the DH-ciphers. Generate this file using:
/usr/bin/openssl dhparam -out /etc/ssl/private/dhparam.pem 4096
It takes a few minutes to generate this file!
3. Updating content
When making sites SSL-only, modern browsers will no longer allow “mixed content”. This can effect staff users that write content for the website. For example, when embedding a YouTube video, the URL should use the https://
protocol prefix. Browsers won’t load the video otherwise. You can also use //
as prefix, so browsers pick the current protocol automatically.
Bonus: you can add Content Security Policy headers to limit the domains for images, scripts, iframes that can be embedded.
Other resources
Other good resources about security:
Michael on January 8, 2016 at 18:51
It would be nice if you had a showcase app people could play with hosted somewhere.
Diederik van der Boor on January 12, 2016 at 10:46
Hi Michael,
Sure!
Right now we don't have an online demo yet. You can however, play with the source of this website locally:
https://github.com/edoburu/django-fluent.org
Let me know whether that works for you!
Best,
Diederik
Diederik van der Boor on June 6, 2016 at 15:33
A brief update, you can find a live demo at https://demo.django-fluent.org/