Broken Authentication in Django with Mongodb
Broken Authentication in Django with Mongodb — how this specific combination creates or exposes the vulnerability
Broken Authentication occurs when identity verification mechanisms are implemented incorrectly, allowing attackers to compromise credentials, session tokens, or authentication logic. Using Django with MongoDB can increase risk if common authentication patterns are misaligned with how MongoDB handles data and sessions.
Django’s built-in authentication system is designed primarily for relational databases and its contrib.auth models rely on SQL joins and transactions. When MongoDB is used as the primary user store or session backend without careful adaptation, several gaps can appear:
- Password storage and hashing mismatches: If passwords are not hashed with a strong adaptive algorithm before being stored in MongoDB, or if a weak hash is used, attackers can retrieve or brute-force credentials quickly. Storing plain-text or weakly hashed passwords in MongoDB collections is a common misconfiguration.
- Session fixation and insecure session storage: Using MongoDB to store session data can be safe, but if session keys are predictable, transmitted over unencrypted channels, or not invalidated after login or logout, attackers can hijack sessions. Django’s database-backed sessions can be pointed at MongoDB, but the application must enforce secure cookie attributes and HTTPS.
- Improper handling of authentication tokens: JWTs or custom tokens stored in MongoDB without short lifetimes or proper revocation mechanisms can be reused. Without rate limiting on authentication endpoints stored in MongoDB-backed services, credential stuffing and brute-force attacks become easier.
- Lack of robust MFA and insecure default configurations: Django projects using MongoDB might omit multi-factor authentication because the default admin interface is not used, but custom login endpoints may not enforce MFA. MongoDB collections that store user profiles must include fields for MFA secrets and enforce MFA verification in the login flow.
An attacker exploiting these issues might steal session cookies, perform credential reuse, or escalate privileges by manipulating user documents in MongoDB. For example, a missing index on username with a non-unique constraint can allow duplicate accounts or make enumeration easier. Without proper input validation on MongoDB queries, login endpoints can be abused through NoSQL injection techniques to bypass authentication checks.
Mongodb-Specific Remediation in Django — concrete code fixes
To secure authentication when using Django with MongoDB, apply strict controls on credential storage, session handling, and query construction. Below are concrete, safe patterns with realistic MongoDB code examples for Django.
- Secure password hashing and MongoDB storage: Always hash passwords with a strong, adaptive function before persisting to MongoDB. Use
bcryptorargon2via Django-compatible libraries and store only the hash in a dedicated user collection.
import bcrypt
from django.conf import settings
def create_user_in_mongo(username, raw_password):
hashed = bcrypt.hashpw(raw_password.encode('utf-8'), bcrypt.gensalt(rounds=12))
user_doc = {
'username': username,
'password_hash': hashed.decode('utf-8'),
'email': f'{username}@example.com',
'is_active': True,
'mfa_enabled': False,
'mfa_secret': None
}
# Assuming `users` is a pymongo collection accessible via a Django service
from myapp.mongo_client import get_collection
users = get_collection('users')
result = users.insert_one(user_doc)
return result.inserted_id
- Safe login verification and NoSQL injection prevention: Use parameterized queries and avoid string interpolation in MongoDB operations. Validate and sanitize all inputs before building queries.
from myapp.mongo_client import get_collection
def verify_user_login(username, password):
users = get_collection('users')
# Use a dictionary filter, never concatenate strings to form a query
user = users.find_one({'username': username})
if user and bcrypt.checkpw(password.encode('utf-8'), user['password_hash'].encode('utf-8')):
return user
return None
- Secure session management with MongoDB: Configure Django to use MongoDB-backed sessions with secure cookie attributes and short session expiry. Ensure session keys are cryptographically random and rotated on privilege changes.
# settings.py relevant snippet
SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # or a custom MongoDB-backed engine
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = 'Lax'
SESSION_COOKIE_AGE = 1800 # 30 minutes
CSRF_COOKIE_SECURE = True
- Token and MFA handling in MongoDB: Store MFA secrets encrypted at rest, set short lifetimes for authentication tokens, and enforce MFA for sensitive operations. Include revocation flags in user documents.
def rotate_session_and_enforce_mfa(user_doc):
from django.contrib.auth import logout
# Invalidate previous sessions by updating a revision token in the user doc
users = get_collection('users')
users.update_one(
{'_id': user_doc['_id']},
{'$set': {'session_rev': user_doc.get('session_rev', 0) + 1}}
)
# Signal Django to logout and require fresh MFA verification
logout(request)
Related CWEs: authentication
| CWE ID | Name | Severity |
|---|---|---|
| CWE-287 | Improper Authentication | CRITICAL |
| CWE-306 | Missing Authentication for Critical Function | CRITICAL |
| CWE-307 | Brute Force | HIGH |
| CWE-308 | Single-Factor Authentication | MEDIUM |
| CWE-309 | Use of Password System for Primary Authentication | MEDIUM |
| CWE-347 | Improper Verification of Cryptographic Signature | HIGH |
| CWE-384 | Session Fixation | HIGH |
| CWE-521 | Weak Password Requirements | MEDIUM |
| CWE-613 | Insufficient Session Expiration | MEDIUM |
| CWE-640 | Weak Password Recovery | HIGH |