Security and Django

Tiago Silva
7 min readMay 1, 2020

--

How many of us are worried about passwords, password checking, and if “it’s safe or not”? Well, I know for a fact that I’m one of them and we all know how much a hacker loves a challenge, don’t we?

Django is pretty cool, out of the box, batteries included web framework for python developers. It is widely used, constantly growing, and maintained by a massive web community and internal team.

But what does it have to do with security?

First, I would like to mention that security nowadays is not a “must” anymore. If you want a business to run smoothly and if you want your clients to trust your product/products, security should be a top priority.

Second, when we talk security we need to mention many layers that can and it should be analyzed (which we won’t cover them all here for obvious reasons).

  • Secure web environment — Modules used, accesses, external scripts, and CSS, underlying operating systems and the list goes on and on.
  • Input Validation — Sanitize everything by assuming that every single input is compromised. The use of the new JS frameworks (Angular, React, VueJS…) is not enough. Everyone can inject and hijack your application with a single input and a click is all you need to compromise your application. No, seriously, one-click is literally what you need.
  • Authentication — Put as many layers as you can to make the life of an attacker harder and harder. As much as you can, it doesn’t hurt you making sure your business is not compromised by malicious attackers.

Authentication

Many people struggle to understand the importance of this subject (myself included sometimes) and how easy is to make mistakes when it comes to design a good authentication system as well as:

  • Forgot Password
  • Recover Password
  • Change Password

And these are just 3 examples of many that use personal and critical credentials.

If you are the same way I was before, please do not try to reinvent the wheel by creating your login system with brand new password encryption algorithm also created by you (unless you are a security expert and your job is looking after these things, of course) for the pleasure of thinking you are a better programmer because of it.

Who never, ever thought the new algorithm from your head will be the next new flavor online that will change the way people encrypt data and you will be forever remembered because of it? Probably no-one but is a nice thought anyway.

There is no need for any of it, nowadays almost every framework provides you out-of-the-box solutions well established in the market that do that same heavy lifting for you.

  • Django — Python
  • Rails — Ruby
  • SpringBoot — Java
  • Entity Framework — .net

And the list goes on and on in other languages.

Django security password

No solution is 100% bulletproof of course but a framework that is highly maintained by a huge amount of people and support is less likely to have errors than a solution that is only developed by one person, correct?

Django, as mentioned before provides out-of-the-box builtins for your project such as the login system. The login usually is composed of an email/username and password. The password can be arbitrary and unique to each user of the application. In the past, Django didn’t have a limit for the password which caused HUGE problems and DDoS attacks and therefore, compromising the application until a limit of 4096 characters was set, reducing substantially this issue.

When it comes to the subject of security passwords, Django provides Password Hashers. What is exactly this? Well, it’s a way of encrypting your password in a unique form and storing somewhere safe without any correlation to the characters introduced in the input box in the first place. Meaning, when a password is provided, runs through a set of transformations and encryptions that maps your input to a bit string of a fixed size. This is a one-way function.

Why is this so important? Well, who doesn’t remember the LinkedIn hack? In 2012, millions of LinkedIn passwords were exposed and hacked compromising nearly 6.5 million accounts worldwide (mine included, unfortunately). LinkedIn often encourages people to change the password somewhat often but we all know that rarely happens. Why 6.5 million accounts were exposed so easily? Well, that was because Linkedin was using an md5 algorithm.

What is md5?

Well, it is simple terms is another algorithm and widely used (checksums, storing UNIX passwords in 128-bit format and so much more) to hash your password but with a small but very dangerous problem, which was what might have caused the Linkedin “leak”. The md5 algorithm doesn’t use any kind of SALT to randomize the passwords, at all. Let’s see an example.

  • User A from the USA uses a password “password123!”. This is a valid password.
  • User B from Spain, User C from Croatia, and User D from Portugal also use the password “password123!”.

Because the passwords can be the same and are not unique in a database(as they shouldn’t for many reasons, hashing them using md5, the result will be b7e283a09511d95d6eac86e39e7942c0 for all of the users with the password “password123!”, even from completely different countries, it doesn’t matter.

You can even copy and paste this password and check yourself, the value will match.

Well, with this in mind and with computer power running some billions of combinations per second, it wasn’t so hard for the attackers to get the passwords and therefore exposing them. This was exactly what happen to LinkedIn.

Salt is a way of helping to randomize the passwords and making them unique, it is like “putting a grain of salt” helping the hash of the password, helping randomize it.

So, for the same example before using the password “password123!” and applying the salt with the hash, the users would have completely different hashes for the same value and the problem of LinkedIn would be easily avoided.

Django does this for you. In your project settings, you can declare.

PASSWORD_HASHERS = [
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
]

This will automatically implement the password hasher’s algorithm to your passwords. Let’s only focus on the PBKDF2 which extends for Password-Based Key Derivation Function 2.

This is a powerful hash used mainly for cryptography and comes with a slightly computational cost (can be slow depending on how many iterations are used) but helps to reduce the vulnerabilities of a brute force attack. So, it is a cost that is worth it if you care about your business and the safety of the users of your platform.

That is it! Is that simple as you don’t need to worry about implementing a whole complex workflow from cryptography to hash by yourself since Django already does it for you. Again, do not reinvent the wheel.

What you could do, is making sure the life of the attackers is harder but reusing the system.

from django.contrib.auth.hashers import PBKDF2SHA1PasswordHasherclass MyCustomPBKDF2SHA1PasswordHasher(PBKDF2SHA1PasswordHasher):
"""
A Subclass of PBKDF2SHA1PasswordHasher that uses 100 times more iterations
This will slow down possible attackers as it makes the the hash more difficult.
Because the computer power increases, the number of iterations could also increase
"""
iterations = PBKDF2SHA1PasswordHasher.iterations * 100

The class itself is self-explanatory and it is not reinventing the wheel, instead, it is using the current wheel and adding some extra iterations but of course at a cost. The time process of validating the login, changing the password, and so on will also increase with the number of iterations, so it is a tradeoff, entirely up to you.

If you opt for this solution, then in the previous setting it should be added as the first entry.

PASSWORD_HASHERS = [
'lib.custom.auth.hashers.MyCustomPBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',,
]

And that’s it, from now on Django will start using your custom class using PBKDF2.

What should I worry about then? Covering the basics.

You should focus on implementing safer workflows when it comes to recovering passwords, changing emails, the authentication process per se.

How? Well, as an example.

  • When a user wants to change the email, why don’t you ask them to do the login again? Amazon and Google do that quite often. This helps to prove that you are you and is not some sort of attack. And the same is for the password, ask the user for the login again.
  • Multistep authentication is also a good way of reducing attacks and preventing the stealing of confidential information. E.g.: Two Factor Authentication, Token Authentication, SMS Authentication, and so many others
  • Avoid sending confidential information to the personal email. Assume the email is always compromised. Even if you opt to use the email for recovering a password, send an email with specific instructions where the user should follow to recover by asking, for example, 2 secrets answers that only the user should know.

Entities such as government and bank institutions will never send you emails asking you to fill a form and change the passwords from there. They will instead use other mechanisms (letters to your home address) to make sure your privacy and security are assured.

The article didn’t even scratch the surface of security on every layer of an application but instead provided some insights about the basics of what each application should have and of course, the examples given and solutions presented are not 100% safe for anybody, each day attackers learn new techniques, new ways of compromising your safety and therefore we should keep updating our ways of doing security.

--

--

Tiago Silva

Entrepreneur, creator of Esmerald ( https://esmerald.dev ), Lilya ( https://lilya.dev) and a lot more widely adopted open source solutions.