I'll analyze this Flask authentication code for security vulnerabilities. This is a comprehensive review without needing external tools.
Security Assessment: Moderate Risk
This code has several good security practices but also contains critical vulnerabilities that would make it unsafe for production use.
π΄ Critical Vulnerabilities
- Weak Password Hashing (SHA-256)
password_hash = hashlib.sha256((password + salt).encode()).hexdigest()Problem: SHA-256 is designed for speed, making it vulnerable to brute-force attacks with modern GPUs (billions of guesses/second).
Fix: Use bcrypt, Argon2, or PBKDF2:
from werkzeug.security import generate_password_hash, check_password_hash
# Store: generate_password_hash(password, method='pbkdf2:sha256:600000')
# Verify: check_password_hash(stored_hash, password)- Timing Attack on Password Verification
return hash_obj.hexdigest() == stored_hashProblem: Standard string comparison leaks timing information, allowing attackers to guess passwords byte-by-byte.
Fix: Use constant-time comparison:
import hmac
return hmac.compare_digest(hash_obj.hexdigest(), stored_hash)- Hardcoded Demo Credentials
'admin': {'password_hash': hashlib.sha256('admin123'.encode()).hexdigest()}Problem: Hardcoded weak passwords (admin123, user123) in source code will end up in git history.
Fix: Remove all default credentials; require setup wizard or environment-based initialization.
π‘ High Severity Issues
- In-Memory Rate Limiting Bypass
login_attempts = {} # Global dictionaryProblem: Reset on every server restart/deploy Doesn't work across multiple server instances (load balancing) Memory exhaustion DoS possible (unbounded IP storage) Fix: Use Redis with expiration:
# Redis EXPIRE automatically cleans old entries
redis.setex(f"login:{ip}", 3600, attempt_count)- X-Forwarded-For IP Spoofing
if request.headers.get('X-Forwarded-For'):
return request.headers.get('X-Forwarded-For').split(',')[0].strip()Problem: Client can spoof any IP by sending X-Forwarded-For: <fake_ip>, bypassing rate limits on others or causing self-blocks. Fix: Only trust specific proxy hops or use request.access_route with trusted proxy configuration.
-
Missing Session Validation The code generates session tokens but never validates them on subsequent requests. There's no @require_auth decorator or session verification middleware. π Medium Severity Issues
-
Debug Mode in Production Template
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)Problem: debug=True exposes stack traces and interactive debugger (PIN-based console) on errors.
- Weak Password Policy
elif len(password) < 6:
errors.append('Password must be at least 6 characters')Problem: 6 characters is insufficient (NIST recommends minimum 8, ideally 12+).
-
No CORS Protection No CORS configuration allows malicious websites to make requests to this API (though SameSite=Lax mitigates cookie-based CSRF).
-
Information Leakage in Registration
if username in USERS_DB:
return jsonify({'error': 'username_exists'}), 409 # Confirms existenceProblem: Allows user enumeration attacks. Should return generic "registration failed" message.
| Feature | Implementation | Status |
|---|---|---|
| Rate limiting | Per-IP attempt tracking | β (but flawed) |
| Account lockout | 5 min after 5 fails | β |
| Secure cookies | HttpOnly, Secure, SameSite | β |
| Input sanitization | Null byte/control char removal | β |
| Generic auth errors | "Invalid username or password" | β |
| Security headers | X-Frame-Options, nosniff | β |
| Token generation | secrets.token_urlsafe | β |
Recommended Fixes (Priority Order)
- Replace SHA-256 with bcrypt/Argon2 immediately
- Add constant-time comparison for password verification
- Implement proper session middleware to validate tokens on protected routes
- Move to Redis for rate limiting storage
- Fix IP extraction to prevent spoofing
- Remove hardcoded credentials and require secure initialization
- Increase minimum password length to 12 characters
- Add request signing or CSRF tokens for state-changing operations
Overall Verdict Not production-ready. The cryptographic weaknesses (SHA-256 + timing attacks) alone are deal-breakers. The code shows security awareness but needs hardening before handling real user data.