Security has three angles:
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.
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.
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 (
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.)
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.
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):