News, ideas and randomness

Securing Django with SSL

Posted: February 18th, 2009 | Author: Scott Barnham | Filed under: Django | 2 Comments »

When we built the centralized authentication system for Red Robot Studios we wanted all authentication and account resources to be available solely over https.

This article covers some tips and tricks we discovered while building the app, and how you can use Django to get fine-grained control as to which resources are available securely.

Why bother with security?

We all know that data sent over http is cleartext and can potentially be read on any network between the client and server. But the risk feels pretty minimal and many sites don’t bother using SSL to encrypt sensitive traffic. For online banking and ecommerce, you’d be crazy not to use it, but for other sites, why bother?

The chances of your http requests being snooped upon by an ISP, intermediate networks or your hosting company seem minimal. But one potentially big risk is users accessing your website on an open wireless network.

For example, perhaps your user has an unsecured wireless home or office network or maybe they use wireless networks in coffee shops and airports: It’s really easy in this situation for sensitive requests to be snooped upon.

The data on your website may not be sensitive, but if you use Django’s admin or authentication frameworks, two important bits of information are passed as cleartext.

When a user logs in, their username and password is posted in cleartext. Assuming login is successful, each subsequent request includes a cookie containing the sessionid. The sessionid is just a random string, but if you know the sessionid of a user, it is trivial to hijack the session and have the same access to the website as that user does until they log out.

Encrypting login sessions

If you want to be sure user credentials and sessions cannot be compromised by eavesdroppers, you need to use SSL encryption. Install an SSL certificate on the server so that traffic is encrypted end-to-end between client and server.

You probably don’t want the whole site to be secure because it will be a lot slower and significantly increase the load on your servers. Instead, you can be selective about which parts of the site should use https instead of http. If you want user sessions to be secure, you should make sure that logging in and all parts of the site that require a logged-in user use https.

SSL

Standard SSL certificates are pretty cheap these days – under $20 per year. We go some from RapidSSLOnline. Each secure site needs its own IP address, so if you’re hosting multiple sites using virtual hosting, you’ll need to look in to getting some dedicated IPs.

There are lots of guides to installing SSL certificates and configuring web servers such as Apache, Lighttpd and Nginx, so I won’t cover that here.

Making Django sessions secure

Django uses cookies for its sessions. When a cookie is set, you can specify that it be a secure cookie, meaning it is only ever passed over https and not in http requests. We can tell Django to use secure cookies for sessions by adding a setting to settings.py

SESSION_COOKIE_SECURE = True

If you set Django to use secure cookies then try to log in over http you will get the error

Looks like your browser isn’t configured to accept cookies. Please enable cookies, reload this page, and try again.”

This happens because Django sets the cookie, but it’s a secure cookie, so when the page loads over http, Django can’t see the cookie and so assumes cookies are disabled in your browser.

Requiring https for admin

To avoid this cookie warning and make sure you only ever pass your admin credentials over https, you can configure your web server so that any http requests are redirected to https.

For example, in Nginx it would look like:

server {
    server_name example.com;
    location /admin {
        # force admin to use https
        rewrite (.*) https://example.com/$1 permanent;
    }
...
}

In Apache, something like:

<Location /admin>
    RewriteRule (.*) https://example.com/$1 [L,R=301]
    ...
</Location>

Of course, these bits of config should go in the http config, not the https config or you will cause infinite redirects!

Requiring https for certain views

If all the logged-in parts of your site are in a certain path (e.g. /accounts/ and /members/) you can configure your web server in the same way to require https for these locations.

If certain views require https (e.g. /members/bert/ is public but /members/bert/edit/ requires login), you may want to check request.is_secure() in those views. A neat way to do it is with a decorator which can also redirect any http requests to https.

from django.conf import settings
from django.http import HttpResponseRedirect

def secure_required(view_func):
    """Decorator makes sure URL is accessed over https."""
    def _wrapped_view_func(request, *args, **kwargs):
        if not request.is_secure():
            if getattr(settings, 'HTTPS_SUPPORT', True):
                request_url = request.build_absolute_uri(request.get_full_path())
                secure_url = request_url.replace('http://', 'https://')
                return HttpResponseRedirect(secure_url)
        return view_func(request, *args, **kwargs)
    return _wrapped_view_func

Then on your view:

@secure_required
@login_required
def edit_member(request, slug):
    ...

Moving between http and https pages

It’s normal to use full path URLs like /accounts/login/ and /blog/. Bear in mind that if you are accessing the site over https and follow one of these links, you will also access them over https. If you want to be explicit, you need to specify the protocol and domain in the links, e.g. https://example.com/accounts/login/ and http://example.co/blog/ .

For $20 and a bit of config, you can secure logged-in sessions on your site and protect yourself and your users from being compromised by eavesdroppers. There are still plenty of sites where this is overkill, but you can see now how easy it is to secure your Django site with SSL.


2 Comments on “Securing Django with SSL”

  1. 1 Requiring https for certain paths in Django | Red Robot Studios said at 12:03 pm on February 6th, 2010:

    [...] while ago I wrote about Securing Django with SSL. Here’s a small [...]

  2. 2 Twitter Updates for 2010-02-06 | Red Robot Studios said at 2:14 pm on February 6th, 2010:

    [...] with my blog post: Securing Django with SSL ( http://www.redrobotstudios.com/blog/2009/02/18/securing-django-with-ssl/ ) [...]


Leave a Reply