Building secure django websites - Erik Romijn

Tags: django, djangocon

Security has three angles:

  • Integrity. Data should not be altered without it being your intention. No corruption

  • Conficentiality. No looted credit card data.

  • Availability. Able to be used or obtained. Security-specific: denial or service attacks.

Cookies are used a lot. Browser sessions, for instance. A cookie header is send to the browser. On the next request to the same domain, the browser sends the cookie contents along. A cookie is basically name/value. A cookie is send if the domain and the (optional) path match. For cookies with the secure flag, the cookie is only send over https.

The browser blindly does this. It doesn’t care what kind of request it is. It simply looks in its cookie jar and sends along all matching cookies.

Cookies are inside the browser, so it is not the best place to store a user id as it might get tampered with. So normally you just store a session id in the cookie. On the server, the session id is translated into a session (with username and so on in it). But this means that stealing somebody’s session ID is almost as valuable as getting his username+password (as long as the cookie session is valid).

A common attack vector is CSRF, cross-site request forgery. You have an innocent-looking form for a newsletter subscription which, in reality, goes to your bank’s website. And if you still have a session cookie for that bank, the request is valid. Including the hidden form fields that tell the bank to tranfer money to the attacker.

Django protects you by using a special csrf_token. This one cannot be faked by the attacker.

A second common attack is XSS injection. Cross site scripting. If you can inject javascript into an image url, for instance. This way you could even extract the local cookies for the page you’re visiting and send them along. So… can you get such a script tag into a website’s search form, for instance? Trick the user? This is called “reflected XSS”.

Perhaps you can also do it wiht “stored XSS”, for instance in blog comments. This is harder, as there are more layers in-between: one of them might catch it.

Django protects you by automatically quoting form data. Especially greater-than, less-than, quotes and ampersand. But watch out when placing such content into javascript, the semicolon isn’t escaped.

Btw, if you set the HTTPOnly flag, it will prevent reading a cookie from javascript. In django 1.4 it is on by default, hurray.

Now on to the server side. The most used attack is SQL injection. What happens if you can add ; DROP TABLE users; to a form field? Is your form input sufficiently quoted? In Django, this is no problem. You’re protected.

But… what if you want to talk to LDAP? You have to build that yourself. Will you escape it enough? So do watch out. And watch out if you pass anything along to a shell call.

And… what about the browser? Is that to be trusted? Does it listen correctly to the httponly flag? Does it keep my cookies safe? So, don’t trust the browser. There have been successful injection attacks by crafting a special http user-agend header because it got logged in some way. And are you sure the sessionid variable in the cookie isn’t '; drop database users;'? Which you might just stuff directly into a session query…

Watch out with django model forms. If you exclude a field in your form, you must make sure you keep excluding fields if you add new dangerous fields. You might have customized the form so you don’t spot the added field. But the user could validly submit it (is_admin=1).

Don’t use plaintext passwords. You’re good with Django, as it properly salts and hashes your password. But many users will still have crappy passwords, so look to limit the amount of tries you can do with a brute-force attack. If you use login, use SSL. (Erik showed part of the http conversation someone had with his django admin interface at the end of the talk, picked up from the unencrypted conference wifi…). Look at django-secure.

A new shiny attack is clickjacking: display a website transparantly, in a frame, on top of the website the user sees. You can hijack a form that way. Django has a middleware to set the proper don’t-display-me-in-frames header.

Backups. If you don’t have a backup, why are you storing it in the first place? And if you have a backup, have you made a restore? Do you keep backups with a different provider? One provider once had a vulnerability that allowed someone to delete lots of virtual machines… Erik speaks from experience…

(For a different summary: I’ve got one of an earlier version of this talk at the Dutch Django meeting.)

Photo & Video Sharing by SmugMug logo

About me

My name is Reinout van Rees and I work a lot with Python (programming language) and Django (website framework). I live in The Netherlands and I'm happily married to Annie van Rees-Kooiman.

Weblog feeds

Most of my website content is in my weblog. You can keep up to date by subscribing to the automatic feeds (for instance with Google reader):