quantum-ai-v3/core/validators.py
Claude 87ec7cc50a 🛡️ Comprehensive Security & Performance Optimization
CRITICAL FIXES:
- 🔴 Remove hardcoded admin passwords (security vulnerability)
- 🔴 Fix SSRF vulnerability in webhook URL validation
- 🔴 Add atomic wallet transactions (race condition fix)
- 🔴 Configure production security headers and CSP
- 🔴 Fix Railway deployment issues (logging import, start command)

SECURITY ENHANCEMENTS:
- 🛡️ Comprehensive input validation and XSS prevention
- 🛡️ Rate limiting on all API endpoints (10-60 req/min)
- 🛡️ Advanced security monitoring middleware
- 🛡️ Suspicious activity detection and logging
- 🛡️ Enhanced HTTPS, HSTS, and cookie security

PERFORMANCE OPTIMIZATIONS:
-  Database query optimization (select_related, indexes)
-  Enhanced Redis caching with proper invalidation
-  Optimized wallet statistics with database aggregation
-  Improved session configuration

INFRASTRUCTURE:
- 📦 New dependencies: bleach, django-ratelimit
- 📊 Enhanced logging with security.log rotation
- 🗃️ Database indexes for performance
- 🔧 Railway-safe deployment configuration

All changes tested and deployment-ready with rollback safety.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-16 14:39:47 +05:30

310 lines
10 KiB
Python

"""
Input validation utilities for security and data integrity.
"""
import re
import bleach
from django.core.exceptions import ValidationError
from django.utils.html import escape
from decimal import Decimal, InvalidOperation
import logging
logger = logging.getLogger('core.security')
class InputValidator:
"""
Comprehensive input validation for security and data integrity.
"""
# Allowed HTML tags for rich text (very restrictive)
ALLOWED_TAGS = ['b', 'i', 'u', 'em', 'strong', 'p', 'br']
ALLOWED_ATTRIBUTES = {}
# Common injection patterns
INJECTION_PATTERNS = [
r'<script[^>]*>.*?</script>', # XSS
r'javascript:', # JavaScript protocol
r'on\w+\s*=', # Event handlers
r'expression\s*\(', # CSS expressions
r'@import', # CSS imports
r'vbscript:', # VBScript
r'data:text/html', # Data URLs
r'SELECT\s+.*FROM', # Basic SQL injection
r'UNION\s+SELECT', # Union SQL injection
r'DROP\s+TABLE', # SQL DROP
r'INSERT\s+INTO', # SQL INSERT
r'DELETE\s+FROM', # SQL DELETE
r'UPDATE\s+.*SET', # SQL UPDATE
r'\|\|\s*1\s*=\s*1', # Boolean SQL injection
r'1\s*=\s*1', # Boolean logic
r'<\s*iframe', # Iframe injection
r'<\s*object', # Object injection
r'<\s*embed', # Embed injection
]
@classmethod
def sanitize_string(cls, value, max_length=1000, allow_html=False):
"""
Sanitize a string input to prevent XSS and injection attacks.
Args:
value: Input string to sanitize
max_length: Maximum allowed length
allow_html: Whether to allow safe HTML tags
Returns:
Sanitized string
Raises:
ValidationError: If input is invalid or malicious
"""
if not isinstance(value, str):
try:
value = str(value)
except:
raise ValidationError("Invalid input type")
# Length check
if len(value) > max_length:
raise ValidationError(f"Input too long (max {max_length} characters)")
# Check for injection patterns
for pattern in cls.INJECTION_PATTERNS:
if re.search(pattern, value, re.IGNORECASE):
logger.warning(f"Potential injection attempt detected: {pattern}")
raise ValidationError("Input contains potentially malicious content")
# HTML sanitization
if allow_html:
# Use bleach to allow only safe HTML
value = bleach.clean(
value,
tags=cls.ALLOWED_TAGS,
attributes=cls.ALLOWED_ATTRIBUTES,
strip=True
)
else:
# Strip all HTML and escape special characters
value = bleach.clean(value, tags=[], strip=True)
value = escape(value)
# Remove null bytes and other control characters
value = value.replace('\x00', '').replace('\r', '').strip()
return value
@classmethod
def validate_email(cls, email):
"""
Validate email address format.
Args:
email: Email address to validate
Returns:
Sanitized email address
Raises:
ValidationError: If email is invalid
"""
if not email or len(email) > 254:
raise ValidationError("Invalid email address")
# Basic email regex (RFC 5322 simplified)
email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
if not re.match(email_pattern, email):
raise ValidationError("Invalid email format")
# Check for dangerous patterns
dangerous_patterns = ['<', '>', '"', "'", '\\', '/', '%', '&']
for pattern in dangerous_patterns:
if pattern in email:
raise ValidationError("Email contains invalid characters")
return email.lower().strip()
@classmethod
def validate_decimal_amount(cls, amount, min_value=0, max_value=10000):
"""
Validate monetary amount.
Args:
amount: Amount to validate (string, int, float, or Decimal)
min_value: Minimum allowed value
max_value: Maximum allowed value
Returns:
Decimal value
Raises:
ValidationError: If amount is invalid
"""
try:
if isinstance(amount, str):
# Remove any non-numeric characters except decimal point
amount = re.sub(r'[^\d.]', '', amount)
decimal_amount = Decimal(str(amount))
# Check range
if decimal_amount < min_value or decimal_amount > max_value:
raise ValidationError(f"Amount must be between {min_value} and {max_value}")
# Check precision (max 2 decimal places for currency)
if decimal_amount.quantize(Decimal('0.01')) != decimal_amount:
raise ValidationError("Amount cannot have more than 2 decimal places")
return decimal_amount
except (InvalidOperation, ValueError, TypeError):
raise ValidationError("Invalid amount format")
@classmethod
def validate_agent_slug(cls, slug):
"""
Validate agent slug format.
Args:
slug: Agent slug to validate
Returns:
Sanitized slug
Raises:
ValidationError: If slug is invalid
"""
if not slug or len(slug) > 100:
raise ValidationError("Invalid agent slug")
# Only allow alphanumeric, hyphens, and underscores
if not re.match(r'^[a-zA-Z0-9\-_]+$', slug):
raise ValidationError("Agent slug contains invalid characters")
return slug.lower().strip()
@classmethod
def validate_json_input(cls, data, max_size=10000):
"""
Validate JSON input data.
Args:
data: Dictionary or JSON string to validate
max_size: Maximum size in bytes
Returns:
Sanitized dictionary
Raises:
ValidationError: If data is invalid
"""
import json
if isinstance(data, str):
try:
data = json.loads(data)
except json.JSONDecodeError:
raise ValidationError("Invalid JSON format")
if not isinstance(data, dict):
raise ValidationError("Input must be a JSON object")
# Check size
json_str = json.dumps(data)
if len(json_str.encode('utf-8')) > max_size:
raise ValidationError(f"Input too large (max {max_size} bytes)")
# Recursively sanitize all string values
sanitized_data = {}
for key, value in data.items():
# Sanitize key
clean_key = cls.sanitize_string(str(key), max_length=100)
# Sanitize value
if isinstance(value, str):
clean_value = cls.sanitize_string(value, max_length=2000)
elif isinstance(value, (int, float, bool)):
clean_value = value
elif isinstance(value, list):
# Sanitize list items (only strings)
clean_value = []
for item in value[:10]: # Limit to 10 items
if isinstance(item, str):
clean_value.append(cls.sanitize_string(item, max_length=500))
elif isinstance(item, (int, float, bool)):
clean_value.append(item)
else:
# Skip complex nested objects
continue
sanitized_data[clean_key] = clean_value
return sanitized_data
@classmethod
def validate_file_upload(cls, uploaded_file, allowed_extensions=None, max_size=10485760):
"""
Validate file upload.
Args:
uploaded_file: Django UploadedFile object
allowed_extensions: List of allowed file extensions
max_size: Maximum file size in bytes (default 10MB)
Returns:
True if valid
Raises:
ValidationError: If file is invalid
"""
if not uploaded_file:
raise ValidationError("No file provided")
# Check file size
if uploaded_file.size > max_size:
raise ValidationError(f"File too large (max {max_size // 1048576}MB)")
# Check file extension
if allowed_extensions:
import os
file_ext = os.path.splitext(uploaded_file.name)[1].lower()
if file_ext not in allowed_extensions:
raise ValidationError(f"File type not allowed. Allowed types: {', '.join(allowed_extensions)}")
# Check filename for malicious patterns
filename = cls.sanitize_string(uploaded_file.name, max_length=255)
# Additional security checks could include:
# - MIME type validation
# - File content scanning
# - Virus scanning
return True
def validate_api_input(request_data):
"""
Validate API request input data.
Args:
request_data: Request data dictionary
Returns:
Sanitized data dictionary
Raises:
ValidationError: If data is invalid
"""
validator = InputValidator()
# Validate common fields
if 'agent_slug' in request_data:
request_data['agent_slug'] = validator.validate_agent_slug(request_data['agent_slug'])
if 'input_data' in request_data:
request_data['input_data'] = validator.validate_json_input(request_data['input_data'])
if 'amount' in request_data:
request_data['amount'] = validator.validate_decimal_amount(request_data['amount'])
return request_data