import hashlib
from flask import Flask, request
@app.route('/register', methods=['POST'])
def register_user():
username = request.form.get('username')
password = request.form.get('password')
# Vulnerable: MD5 without salt
password_hash = hashlib.md5(password.encode()).hexdigest()
# Store in database
store_user(username, password_hash)
return 'User registered'
@app.route('/login', methods=['POST'])
def login_user():
username = request.form.get('username')
password = request.form.get('password')
# Vulnerable: MD5 hash comparison
password_hash = hashlib.md5(password.encode()).hexdigest()
stored_hash = get_user_hash(username)
if password_hash == stored_hash:
return 'Login successful'
return 'Invalid credentials'
# Vulnerable: MD5 with weak salt
def hash_password_weak_salt(password):
salt = '12345' # Static salt - very weak
return hashlib.md5((password + salt).encode()).hexdigest()
import hashlib
import secrets
import bcrypt
from passlib.context import CryptContext
from flask import Flask, request
# Secure password context using multiple strong algorithms
pwd_context = CryptContext(
schemes=['bcrypt', 'pbkdf2_sha256'],
default='bcrypt',
bcrypt__rounds=12, # Strong work factor
pbkdf2_sha256__rounds=100000 # High iteration count
)
@app.route('/register', methods=['POST'])
def register_user():
"""Secure user registration with proper password hashing."""
username = request.form.get('username', '')
password = request.form.get('password', '')
# Validate input
if not username or not password:
return 'Username and password required', 400
# Validate password strength
if len(password) < 8:
return 'Password must be at least 8 characters', 400
try:
# Secure: Use bcrypt with automatic salt generation
password_hash = pwd_context.hash(password)
# Store in database
store_user(username, password_hash)
return 'User registered successfully'
except Exception as e:
return 'Registration failed', 500
@app.route('/login', methods=['POST'])
def login_user():
"""Secure user login with proper hash verification."""
username = request.form.get('username', '')
password = request.form.get('password', '')
if not username or not password:
return 'Username and password required', 400
try:
stored_hash = get_user_hash(username)
if not stored_hash:
return 'Invalid credentials', 401
# Secure: Verify using passlib context
if pwd_context.verify(password, stored_hash):
# Check if hash needs upgrading
if pwd_context.needs_update(stored_hash):
new_hash = pwd_context.hash(password)
update_user_hash(username, new_hash)
return 'Login successful'
else:
return 'Invalid credentials', 401
except Exception as e:
return 'Login failed', 500
# Alternative: Manual bcrypt implementation
def secure_hash_password_bcrypt(password):
"""Secure password hashing using bcrypt."""
if isinstance(password, str):
password = password.encode('utf-8')
# Generate salt and hash (cost factor 12)
salt = bcrypt.gensalt(rounds=12)
return bcrypt.hashpw(password, salt).decode('utf-8')
def verify_password_bcrypt(password, hashed):
"""Verify password against bcrypt hash."""
if isinstance(password, str):
password = password.encode('utf-8')
if isinstance(hashed, str):
hashed = hashed.encode('utf-8')
return bcrypt.checkpw(password, hashed)
# Alternative: PBKDF2 implementation
def secure_hash_password_pbkdf2(password):
"""Secure password hashing using PBKDF2-SHA256."""
# Generate random salt
salt = secrets.token_bytes(32)
# Hash with PBKDF2-SHA256
key = hashlib.pbkdf2_hmac(
'sha256',
password.encode('utf-8'),
salt,
100000 # 100k iterations
)
# Return salt + hash for storage
return salt.hex() + ':' + key.hex()
def verify_password_pbkdf2(password, stored_hash):
"""Verify password against PBKDF2 hash."""
try:
salt_hex, key_hex = stored_hash.split(':', 1)
salt = bytes.fromhex(salt_hex)
stored_key = bytes.fromhex(key_hex)
# Hash provided password with same salt
key = hashlib.pbkdf2_hmac(
'sha256',
password.encode('utf-8'),
salt,
100000
)
# Constant-time comparison
return secrets.compare_digest(key, stored_key)
except ValueError:
return False
# Alternative: Argon2 implementation (requires argon2-cffi)
def secure_hash_password_argon2(password):
"""Secure password hashing using Argon2."""
try:
from argon2 import PasswordHasher
ph = PasswordHasher(
time_cost=3, # Number of iterations
memory_cost=65536, # Memory usage in KB
parallelism=1, # Number of threads
hash_len=32, # Hash length
salt_len=16 # Salt length
)
return ph.hash(password)
except ImportError:
raise RuntimeError('argon2-cffi library required for Argon2')
def verify_password_argon2(password, hashed):
"""Verify password against Argon2 hash."""
try:
from argon2 import PasswordHasher
from argon2.exceptions import VerifyMismatchError
ph = PasswordHasher()
try:
ph.verify(hashed, password)
return True
except VerifyMismatchError:
return False
except ImportError:
raise RuntimeError('argon2-cffi library required for Argon2')
# Migration helper for upgrading from MD5
def migrate_md5_hash(username, old_md5_hash, new_password=None):
"""Migrate user from MD5 to secure hash on next login."""
if new_password:
# User provided password, upgrade immediately
new_hash = pwd_context.hash(new_password)
update_user_hash(username, new_hash)
return True
else:
# Mark for upgrade on next successful login
mark_user_for_hash_upgrade(username)
return False
@app.route('/admin/migrate_hashes', methods=['POST'])
def admin_migrate_hashes():
"""Admin endpoint to force hash migration."""
# This would typically require admin authentication
if not is_admin(request):
return 'Unauthorized', 403
users_migrated = 0
users_marked = 0
for user in get_all_users():
if is_md5_hash(user['password_hash']):
# Can't migrate without password, mark for upgrade
mark_user_for_hash_upgrade(user['username'])
users_marked += 1
return {
'users_marked_for_upgrade': users_marked,
'message': 'Users will be upgraded on next successful login'
}
# Helper functions
def is_md5_hash(hash_string):
"""Check if hash looks like MD5."""
return len(hash_string) == 32 and all(c in '0123456789abcdef' for c in hash_string.lower())
def store_user(username, password_hash):
"""Store user in database."""
# Database implementation
pass
def get_user_hash(username):
"""Get user hash from database."""
# Database implementation
pass
def update_user_hash(username, new_hash):
"""Update user hash in database."""
# Database implementation
pass