LetsTryGPT/agent4-implementation
0
1import { Request, Response, NextFunction } from 'express';2import { logger } from '../utils';3 4/**5 * Enterprise Security Headers Middleware6 * Implements OWASP recommended security headers7 *8 * Reference: https://owasp.org/www-project-secure-headers/9 */10export function securityHeaders(req: Request, res: Response, next: NextFunction): void {11 // Prevent clickjacking attacks12 res.setHeader('X-Frame-Options', 'DENY');13 14 // Enable XSS protection in legacy browsers15 res.setHeader('X-XSS-Protection', '1; mode=block');16 17 // Prevent MIME type sniffing18 res.setHeader('X-Content-Type-Options', 'nosniff');19 20 // Control referrer information21 res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');22 23 // Content Security Policy - Strict policy for API server24 res.setHeader(25 'Content-Security-Policy',26 "default-src 'none'; frame-ancestors 'none'; base-uri 'none'"27 );28 29 // Permissions Policy (formerly Feature-Policy)30 res.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=(), payment=()');31 32 // Strict Transport Security (HSTS) - Only if behind HTTPS33 // 2 years max-age with preload for production34 if (req.secure || req.headers['x-forwarded-proto'] === 'https') {35 res.setHeader('Strict-Transport-Security', 'max-age=63072000; includeSubDomains; preload');36 }37 38 // Remove X-Powered-By header to hide Express39 res.removeHeader('X-Powered-By');40 41 next();42}43 44/**45 * Request sanitization middleware46 * Validates and sanitizes common attack vectors47 */48export function sanitizeRequest(req: Request, res: Response, next: NextFunction): void {49 const requestId = req.headers['x-request-id'] as string;50 51 // Check for suspicious patterns in headers52 const suspiciousHeaderPatterns = [53 /<script/i,54 /javascript:/i,55 /onerror=/i,56 /onclick=/i,57 /\.\.[\\/]/i, // Path traversal (.. followed by / or \)58 /%2e%2e%2f/i, // URL encoded path traversal (../)59 /%2e%2e%5c/i, // URL encoded path traversal (..\)60 ];61 62 // Skip infrastructure headers from security checks63 const infrastructureHeaders = new Set([64 'x-vercel-id',65 'x-vercel-cache',66 'x-forwarded-for',67 'x-forwarded-proto',68 'x-forwarded-host',69 'x-real-ip',70 'via',71 'forwarded',72 ]);73 74 for (const [headerName, headerValue] of Object.entries(req.headers)) {75 // Skip infrastructure headers76 if (infrastructureHeaders.has(headerName.toLowerCase())) {77 continue;78 }79 80 if (typeof headerValue === 'string') {81 for (const pattern of suspiciousHeaderPatterns) {82 if (pattern.test(headerValue)) {83 logger.warn('Suspicious header pattern detected', {84 requestId,85 header: headerName,86 pattern: pattern.toString(),87 ip: req.ip,88 });89 90 res.status(400).json({91 success: false,92 error: 'Invalid request headers',93 requestId,94 });95 return;96 }97 }98 }99 }100 101 // Check for SQL injection patterns in query parameters102 if (req.query && Object.keys(req.query).length > 0) {103 const sqlInjectionPatterns = [104 /(\bOR\b|\bAND\b).*=.*=/i,105 /UNION.*SELECT/i,106 /DROP\s+TABLE/i,107 /INSERT\s+INTO/i,108 /DELETE\s+FROM/i,109 /UPDATE.*SET/i,110 /--/,111 /;.*--/,112 /\/\*/,113 ];114 115 const queryString = JSON.stringify(req.query);116 for (const pattern of sqlInjectionPatterns) {117 if (pattern.test(queryString)) {118 logger.warn('Potential SQL injection attempt detected', {119 requestId,120 query: req.query,121 pattern: pattern.toString(),122 ip: req.ip,123 });124 125 res.status(400).json({126 success: false,127 error: 'Invalid query parameters',128 requestId,129 });130 return;131 }132 }133 }134 135 next();136}137 138/**139 * IP validation and rate limiting bypass prevention140 * Ensures X-Forwarded-For header is not spoofed141 */142export function validateClientIP(req: Request, _res: Response, next: NextFunction): void {143 const requestId = req.headers['x-request-id'] as string;144 145 // Log actual client IP for security monitoring146 const clientIP = req.ip || req.socket.remoteAddress || 'unknown';147 const forwardedFor = req.headers['x-forwarded-for'];148 149 // Detect potential IP spoofing attempts150 if (forwardedFor && typeof forwardedFor === 'string') {151 const ips = forwardedFor.split(',').map((ip) => ip.trim());152 if (ips.length > 5) {153 logger.warn('Suspicious X-Forwarded-For chain detected', {154 requestId,155 chain: ips,156 clientIP,157 });158 }159 }160 161 // Store validated IP for rate limiting162 req.headers['x-client-ip'] = clientIP;163 164 next();165}166 167/**168 * Request timeout middleware169 * Prevents slowloris and similar DoS attacks170 */171export function requestTimeout(timeoutMs: number = 30000) {172 return function (req: Request, res: Response, next: NextFunction): void {173 const requestId = req.headers['x-request-id'] as string;174 175 // Set timeout for the request176 const timer = setTimeout(() => {177 if (!res.headersSent) {178 logger.warn('Request timeout', {179 requestId,180 url: req.url,181 method: req.method,182 timeout: timeoutMs,183 });184 185 res.status(408).json({186 success: false,187 error: 'Request timeout',188 requestId,189 });190 }191 }, timeoutMs);192 193 // Clear timeout when response is sent194 res.on('finish', () => clearTimeout(timer));195 res.on('close', () => clearTimeout(timer));196 197 next();198 };199}200 201/**202 * JSON payload validation203 * Prevents JSON injection and oversized payloads204 */205export function validateJSONPayload(req: Request, res: Response, next: NextFunction): void {206 const requestId = req.headers['x-request-id'] as string;207 208 // Check content-type for JSON endpoints209 if (req.method === 'POST' || req.method === 'PUT' || req.method === 'PATCH') {210 const contentType = req.headers['content-type'];211 212 if (contentType && !contentType.includes('application/json')) {213 logger.warn('Invalid content-type for JSON endpoint', {214 requestId,215 contentType,216 method: req.method,217 url: req.url,218 });219 220 res.status(415).json({221 success: false,222 error: 'Unsupported Media Type. Expected application/json',223 requestId,224 });225 return;226 }227 }228 229 next();230}231 232/**233 * Comprehensive security middleware suite234 * Apply all security measures in correct order235 */236export const securityMiddleware = [237 securityHeaders,238 validateClientIP,239 sanitizeRequest,240 validateJSONPayload,241 requestTimeout(30000), // 30 second timeout for LLM requests242];243 