(One of my summaries of a talk at the 2015 django under the hood conference).
Florian Apolloner talks about django security. Django security, so it won’t be about attacks against the SSL protocol as those are outside of django. (But do look at https://www.ssllabs.com/ssltest/).
In case you think you’ve found a security bug in django: look at
https://djangoproject.com/security and only contact
security@djangoproject.com
. Don’t report such a bug publicly, as that
makes it much harder to make and distribute a proper fix.
Regarding security: look at the owasp top 10 list of the most common found vulnerabilities in websites.
Basic rule: don’t ever trust user input. Everything the user can input into
your web interface is to be treated as dangerous. select * from auth_user
where username=%s
is easy to exploit if you inject a username string
inputted by the user directly.
If you use django, you don’t run much risk as django does the good thing internally regarding escaping.
Defense in layers is best. If you limit the parameter to an integer in your url patterns and select users by id instead of a string, you already prevent many problems.
The same goes for OS interaction. Use Django components instead of rolling your own storage or email. Django’s components are secure. If there’s no django component to do it, like ldap authentication: watch out as you’re on your own.
Generally: string interpolations are bad.
To repeat: do not ever trust user input. This includes everything the user sends, including http headers and filenames/content types in uploads.
Basic rule: use what django provides. Django does a lot to keep you safe. He showed some examples.
Passwords are stored encrypted. Multiple algorithms are available out of the box. Iterations are increased every release. Upgrading to new algorithms are always possible.
Since django 1.9 you can have password validators. Length checks, numeric characters, common words. And you can add your own. Please use them.
Django allows pasword reset links to be used. For this, nothing needs to be stored on the server. A link is mailed to the user. The link can be used once and only once to reset the password.
The link includes a user ID, a timestamp and an HMAC hash of your last login
time and two other items. You can look at django.core.signing.*
if you
need to roll your own.
A lot of XSS is prevented by django’s auto-escaping. But: it is HTML only. It
replaces < > ' "
with entities. Always use quotes around attributes.
Javascript requires different escaping! var mystr="{{ value|escapejs}}"
.
The canonical XSS attack results in something like
data="</script><script>alert('xss')'//"
.
If you want to insert json inside a template:
var json = JSON.parse('{{ data|escapejs }}');
Or you can use django-argonauts:
var json = {{ data|json }};
Defense in depth: you can enable django’s XSS protection. It enables a http header that tells your browser to be extra picky about what it allows: no inline js, no event handlers.
The most important thing: check your libraries and your own code. Many
people just do mark_safe(json.dumps()
. Many many people.
Basically: <img src="mybank.com/t/?amount=1000&to=apollo13">
.
It is enabled by default. It protects your site against an attacker sending one of your users to your site with a hurtful request. Django protects against it by generating a random value in the form and setting one in your cookie. If you go directly to the form and submit it, everything compares. If you come from a different site, they don’t match.
This means requests to /auth/login/?next=http://evil.com
. After login you
are on evil.com. So use django.utils.http.is_safe_url()
. It contains more
comments than code, which means that it is code that is hard to get right :-)
Run manage.py check --deploy
and try to get everything right. It checks
for security settings that you might have missed.
What more could we do in Django?
Rate limiting for login and so.
Two factor authentication. (TOTP and U2F as reference implementations).
CSRF improvmeents (#16859).
JSON filter for templates. This will be added to django core.
Enhance SecurityMiddleware. (Look at https://github.com/twitter/secureheaders)
Implement Content-Security-Policy.
Limit POST/GET data length.
Image: repairing a locomotive
My name is Reinout van Rees and I program in Python, I live in the Netherlands, I cycle recumbent bikes and I have a model railway.
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):