""" Security middleware for enhanced security headers and CSP. """ from django.conf import settings from django.utils import timezone import logging logger = logging.getLogger('core.security') class SecurityHeadersMiddleware: """ Middleware to add comprehensive security headers to all responses. Implements Content Security Policy, security headers, and security monitoring. """ def __init__(self, get_response): self.get_response = get_response def __call__(self, request): response = self.get_response(request) # Content Security Policy if not settings.DEBUG: # Check if this is a direct access agent page that needs external frames is_direct_access_page = ( '/agents/' in request.path and request.path.count('/') >= 3 and not request.path.endswith('/api/execute/') ) if is_direct_access_page: # Relaxed CSP for direct access agent pages (external forms) csp_policy = ( "default-src 'self'; " "script-src 'self' 'unsafe-inline' https://js.stripe.com https://checkout.stripe.com https://form.jotform.com https://www.jotform.com https://agent.jotform.com https://cdn.jotfor.ms; " "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://form.jotform.com https://www.jotform.com https://agent.jotform.com https://cdn.jotfor.ms; " "font-src 'self' https://fonts.gstatic.com https://form.jotform.com https://www.jotform.com https://agent.jotform.com https://cdn.jotfor.ms; " "img-src 'self' data: https: blob:; " "connect-src 'self' https: wss: ws:; " "frame-src 'self' https: http:; " "child-src 'self' https: http:; " "object-src 'none'; " "base-uri 'self'; " "form-action 'self' https: http:; " "frame-ancestors 'none';" ) else: # Production CSP - Strict security for other pages csp_policy = ( "default-src 'self'; " "script-src 'self' 'unsafe-inline' https://js.stripe.com https://checkout.stripe.com; " "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; " "font-src 'self' https://fonts.gstatic.com; " "img-src 'self' data: https: blob:; " "connect-src 'self' https://api.stripe.com https://checkout.stripe.com; " "frame-src 'self' https://js.stripe.com https://hooks.stripe.com; " "object-src 'none'; " "base-uri 'self'; " "form-action 'self'; " "frame-ancestors 'none'; " "upgrade-insecure-requests;" ) else: # Development CSP - More permissive for development tools csp_policy = ( "default-src 'self' 'unsafe-inline' 'unsafe-eval'; " "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://js.stripe.com; " "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; " "font-src 'self' https://fonts.gstatic.com; " "img-src 'self' data: https: blob:; " "connect-src 'self' ws: wss: https:; " "frame-src 'self' https: http:;" ) response['Content-Security-Policy'] = csp_policy # Additional Security Headers response['X-Content-Type-Options'] = 'nosniff' response['X-XSS-Protection'] = '1; mode=block' response['Referrer-Policy'] = 'strict-origin-when-cross-origin' response['Permissions-Policy'] = ( 'geolocation=(), microphone=(), camera=(), ' 'payment=(self "https://js.stripe.com"), ' 'usb=(), magnetometer=(), gyroscope=(), accelerometer=()' ) # X-Frame-Options handling if request.path.endswith('/display/') and '/agents/' in request.path: # Allow direct access agent display pages to be framed (they contain external iframes) response['X-Frame-Options'] = 'SAMEORIGIN' else: # Deny framing for all other pages response['X-Frame-Options'] = 'DENY' # Security for critical pages if request.path.startswith('/admin/') or request.path.startswith('/wallet/'): response['X-Frame-Options'] = 'DENY' response['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0' response['Pragma'] = 'no-cache' response['Expires'] = '0' # Log security events for monitoring if hasattr(request, 'user') and request.user.is_authenticated: # Log administrative actions if request.path.startswith('/admin/') and request.method == 'POST': logger.info(f"Admin action by user {request.user.id} from IP {request.META.get('REMOTE_ADDR')}") # Log sensitive financial operations if request.path.startswith('/wallet/') and request.method == 'POST': logger.info(f"Wallet operation by user {request.user.id} from IP {request.META.get('REMOTE_ADDR')}") # Log agent executions if request.path.startswith('/agents/api/execute') and request.method == 'POST': logger.info(f"Agent execution by user {request.user.id} from IP {request.META.get('REMOTE_ADDR')}") # Log authentication failures if hasattr(request, 'user') and not request.user.is_authenticated: if request.path.startswith('/auth/') and request.method == 'POST': logger.warning(f"Failed authentication attempt from IP {request.META.get('REMOTE_ADDR')}") return response class SecurityMonitoringMiddleware: """ Middleware for security event monitoring and threat detection. """ def __init__(self, get_response): self.get_response = get_response self.suspicious_patterns = [ '.env', 'wp-admin', 'phpmyadmin', '../', '= 5: self.suspicious_ips.add(ip) self._log_security_event( request, 'suspicious_ip_detected', f"IP {ip} marked suspicious after {self.failed_attempts[ip]['count']} failed attempts" ) def _log_security_event(self, request, event_type, details): """Log security events for monitoring""" ip = request.META.get('REMOTE_ADDR', 'unknown') user_id = request.user.id if hasattr(request, 'user') and request.user.is_authenticated else 'anonymous' user_agent = request.META.get('HTTP_USER_AGENT', '')[:100] # Enhanced logging with more context logger.warning( f"Security Event: {event_type} - " f"IP: {ip} - " f"User: {user_id} - " f"Path: {request.path} - " f"Method: {request.method} - " f"UA: {user_agent} - " f"Referer: {request.META.get('HTTP_REFERER', 'none')[:100]} - " f"Details: {details}" ) # Additional context for critical events if event_type in ['suspicious_request', 'potential_sqli', 'suspicious_ip_detected']: logger.critical( f"CRITICAL SECURITY ALERT: {event_type} - " f"IP: {ip} - User: {user_id} - {details}" )