BudiBadu Logo
Samplebadu

Django by Example: Password Hashing

Django 5.0+

Django never stores passwords in plain text. It uses the PBKDF2 algorithm with a SHA256 hash by default. This example shows how to manually hash passwords and check them, which is useful for custom user creation flows.

Code

from django.contrib.auth.hashers import make_password, check_password

# 1. Hashing a password (e.g., during Sign Up)
raw_password = "MySecretPassword123!"
hashed_password = make_password(raw_password)

print(hashed_password)
# Output looks like:
# pbkdf2_sha256$600000$HqX...$2sF...
# algorithm$iterations$salt$hash

# 2. Verifying a password (e.g., custom login)
is_correct = check_password("MySecretPassword123!", hashed_password)
print(f"Password matches: {is_correct}") # True

is_wrong = check_password("WrongPass", hashed_password)
print(f"Password matches: {is_wrong}") # False

# 3. Creating a user manually (Best Practice)
from django.contrib.auth.models import User

# DON'T do this:
# User.objects.create(username='u', password='raw_password') 
# This stores plain text!

# DO this:
user = User.objects.create_user(
    username='john',
    email='[email protected]',
    password='raw_password' # create_user handles hashing automatically
)
# OR
user = User(username='jane')
user.set_password('raw_password') # Hashes it
user.save()

Explanation

Security is a core tenet of Django, and nowhere is this more evident than in password handling. Django never stores passwords in plain text. Instead, it uses a one-way cryptographic hash function. By default, this is PBKDF2 with a SHA256 digest, a robust algorithm designed to be computationally expensive to slow down brute-force attacks.

The hash format algorithm$iterations$salt$hash includes everything needed to verify the password later. The salt is a random string added to the password before hashing to prevent rainbow table attacks. The iterations (work factor) determine how many times the hash function is applied; Django increases this default over time as hardware becomes faster.

When creating users programmatically, you must use User.objects.create_user() (which calls make_password() internally) rather than User.objects.create(). The latter would store the raw password string in the database, leaving your users vulnerable. check_password() is the safe way to verify credentials, handling the salt and hashing algorithm automatically.

Code Breakdown

5
make_password(). Takes a plain string and returns the long hash string. It generates a random salt automatically every time it runs.
13
check_password(). You cannot "decrypt" a hash. Instead, this function hashes the input password using the same salt found in the stored hash and compares the results.
27
create_user(). This helper method is the standard way to create users. It ensures the password is hashed before saving to the DB.
34
user.set_password(). If you are updating a password (e.g., "Change Password" form), use this method on the user instance, followed by user.save().