135 lines
4.2 KiB
Python
135 lines
4.2 KiB
Python
"""
|
|
Security utilities for encryption and data protection.
|
|
"""
|
|
from cryptography.fernet import Fernet
|
|
from django.conf import settings
|
|
import base64
|
|
import hashlib
|
|
import os
|
|
|
|
|
|
class DataEncryption:
|
|
"""
|
|
Encrypt/decrypt sensitive data.
|
|
"""
|
|
@staticmethod
|
|
def get_encryption_key():
|
|
"""Get or generate encryption key."""
|
|
key = getattr(settings, 'ENCRYPTION_KEY', None)
|
|
if not key:
|
|
# Generate a key (in production, this should be in environment)
|
|
key = Fernet.generate_key()
|
|
elif isinstance(key, str):
|
|
key = key.encode()
|
|
return key
|
|
|
|
@staticmethod
|
|
def encrypt(data):
|
|
"""Encrypt sensitive data."""
|
|
if not data:
|
|
return data
|
|
try:
|
|
key = DataEncryption.get_encryption_key()
|
|
f = Fernet(key)
|
|
encrypted = f.encrypt(data.encode() if isinstance(data, str) else data)
|
|
return base64.urlsafe_b64encode(encrypted).decode()
|
|
except Exception:
|
|
return data # Return original if encryption fails
|
|
|
|
@staticmethod
|
|
def decrypt(encrypted_data):
|
|
"""Decrypt sensitive data."""
|
|
if not encrypted_data:
|
|
return encrypted_data
|
|
try:
|
|
key = DataEncryption.get_encryption_key()
|
|
f = Fernet(key)
|
|
decoded = base64.urlsafe_b64decode(encrypted_data.encode())
|
|
decrypted = f.decrypt(decoded)
|
|
return decrypted.decode()
|
|
except Exception:
|
|
return encrypted_data # Return original if decryption fails
|
|
|
|
|
|
class InputSanitizer:
|
|
"""
|
|
Sanitize user input to prevent XSS and injection attacks.
|
|
"""
|
|
@staticmethod
|
|
def sanitize_html(text):
|
|
"""Remove potentially dangerous HTML."""
|
|
if not text:
|
|
return text
|
|
|
|
import html
|
|
# Escape HTML entities
|
|
text = html.escape(text)
|
|
return text
|
|
|
|
@staticmethod
|
|
def sanitize_sql(text):
|
|
"""Basic SQL injection prevention (Django ORM handles this, but extra check)."""
|
|
if not text:
|
|
return text
|
|
|
|
# Remove SQL keywords
|
|
dangerous = ['DROP', 'DELETE', 'INSERT', 'UPDATE', 'SELECT', 'UNION', '--', ';']
|
|
text_upper = text.upper()
|
|
for keyword in dangerous:
|
|
if keyword in text_upper:
|
|
# Log potential SQL injection attempt
|
|
return None
|
|
return text
|
|
|
|
@staticmethod
|
|
def validate_email(email):
|
|
"""Validate email format."""
|
|
import re
|
|
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
|
|
return bool(re.match(pattern, email))
|
|
|
|
@staticmethod
|
|
def validate_url(url):
|
|
"""Validate URL format."""
|
|
import re
|
|
pattern = r'^https?://[^\s/$.?#].[^\s]*$'
|
|
return bool(re.match(pattern, url))
|
|
|
|
|
|
class PasswordSecurity:
|
|
"""
|
|
Enhanced password security utilities.
|
|
"""
|
|
@staticmethod
|
|
def check_password_strength(password):
|
|
"""Check password strength."""
|
|
if len(password) < 12:
|
|
return False, "Password must be at least 12 characters long"
|
|
|
|
if not any(c.isupper() for c in password):
|
|
return False, "Password must contain at least one uppercase letter"
|
|
|
|
if not any(c.islower() for c in password):
|
|
return False, "Password must contain at least one lowercase letter"
|
|
|
|
if not any(c.isdigit() for c in password):
|
|
return False, "Password must contain at least one number"
|
|
|
|
if not any(c in "!@#$%^&*()_+-=[]{}|;:,.<>?" for c in password):
|
|
return False, "Password must contain at least one special character"
|
|
|
|
# Check for common patterns
|
|
common_patterns = ['123456', 'password', 'qwerty', 'abc123']
|
|
password_lower = password.lower()
|
|
for pattern in common_patterns:
|
|
if pattern in password_lower:
|
|
return False, "Password contains common patterns"
|
|
|
|
return True, "Password is strong"
|
|
|
|
@staticmethod
|
|
def hash_sensitive_data(data):
|
|
"""Hash sensitive data for storage."""
|
|
return hashlib.sha256(data.encode()).hexdigest()
|
|
|