Files
AI-Proxy-Worker/docs/Security.en.md
2025-08-17 19:59:10 +08:00

12 KiB

Security Configuration

🌍 Language / 语言

🇺🇸 English | 🇨🇳 中文

Comprehensive security guide for deploying AI Proxy Worker in production environments. Follow these best practices to ensure your deployment is secure and protected against common threats.

🔐 Authentication & Authorization

API Key Security

Protect your AI service API keys:

// ✅ Good: Store in Cloudflare secrets
wrangler secret put DEEPSEEK_API_KEY

// ❌ Bad: Never hardcode in source code
const API_KEY = "sk-1234567890abcdef"; // NEVER DO THIS

Proxy Key Configuration

Set up secure proxy access:

// Strong proxy key generation
const PROXY_KEY = crypto.randomUUID() + crypto.randomUUID();

// Set as Cloudflare secret
wrangler secret put PROXY_KEY

Multi-tier Authentication

Implement layered security:

async function authenticateRequest(request, env) {
  const authHeader = request.headers.get('Authorization');
  
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return { valid: false, error: 'Missing or invalid authorization header' };
  }
  
  const token = authHeader.substring(7);
  
  // Verify proxy key
  if (token !== env.PROXY_KEY) {
    return { valid: false, error: 'Invalid proxy key' };
  }
  
  return { valid: true };
}

🛡️ Input Validation & Sanitization

Request Validation

Validate all incoming requests:

function validateChatRequest(data) {
  const errors = [];
  
  // Required fields
  if (!data.messages || !Array.isArray(data.messages)) {
    errors.push('messages must be an array');
  }
  
  if (!data.model || typeof data.model !== 'string') {
    errors.push('model must be a string');
  }
  
  // Message validation
  data.messages?.forEach((msg, index) => {
    if (!msg.role || !['user', 'assistant', 'system'].includes(msg.role)) {
      errors.push(`messages[${index}].role must be user, assistant, or system`);
    }
    
    if (!msg.content || typeof msg.content !== 'string') {
      errors.push(`messages[${index}].content must be a non-empty string`);
    }
    
    // Content length limits
    if (msg.content.length > 100000) {
      errors.push(`messages[${index}].content exceeds maximum length`);
    }
  });
  
  // Parameter validation
  if (data.temperature !== undefined) {
    if (typeof data.temperature !== 'number' || data.temperature < 0 || data.temperature > 2) {
      errors.push('temperature must be a number between 0 and 2');
    }
  }
  
  return {
    valid: errors.length === 0,
    errors
  };
}

Content Filtering

Implement content safety checks:

function containsUnsafeContent(text) {
  const unsafePatterns = [
    /\b(password|secret|key|token)\s*[:=]\s*\w+/i,
    /\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/, // Credit card patterns
    /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/ // Email patterns (if needed)
  ];
  
  return unsafePatterns.some(pattern => pattern.test(text));
}

// Usage in request handler
if (containsUnsafeContent(message.content)) {
  return new Response(JSON.stringify({
    error: 'content_rejected',
    message: 'Request contains potentially unsafe content'
  }), { status: 400 });
}

🚫 Rate Limiting & DDoS Protection

Request Rate Limiting

Implement rate limiting to prevent abuse:

class RateLimiter {
  constructor(maxRequests = 100, windowMs = 60000) {
    this.maxRequests = maxRequests;
    this.windowMs = windowMs;
    this.requests = new Map();
  }
  
  isAllowed(clientId) {
    const now = Date.now();
    const windowStart = now - this.windowMs;
    
    // Clean old entries
    for (const [id, timestamps] of this.requests.entries()) {
      const validTimestamps = timestamps.filter(ts => ts > windowStart);
      if (validTimestamps.length === 0) {
        this.requests.delete(id);
      } else {
        this.requests.set(id, validTimestamps);
      }
    }
    
    // Check current client
    const clientRequests = this.requests.get(clientId) || [];
    const recentRequests = clientRequests.filter(ts => ts > windowStart);
    
    if (recentRequests.length >= this.maxRequests) {
      return false;
    }
    
    // Add current request
    recentRequests.push(now);
    this.requests.set(clientId, recentRequests);
    
    return true;
  }
  
  getRemainingRequests(clientId) {
    const clientRequests = this.requests.get(clientId) || [];
    const windowStart = Date.now() - this.windowMs;
    const recentRequests = clientRequests.filter(ts => ts > windowStart);
    
    return Math.max(0, this.maxRequests - recentRequests.length);
  }
}

// Usage
const rateLimiter = new RateLimiter(100, 60000); // 100 requests per minute

async function handleRequest(request, env) {
  const clientId = getClientId(request);
  
  if (!rateLimiter.isAllowed(clientId)) {
    return new Response(JSON.stringify({
      error: 'rate_limit_exceeded',
      message: 'Too many requests. Please try again later.',
      retryAfter: 60
    }), {
      status: 429,
      headers: {
        'Content-Type': 'application/json',
        'Retry-After': '60'
      }
    });
  }
  
  // Process request...
}

IP-based Protection

Implement IP-based security measures:

function getClientIP(request) {
  return request.headers.get('CF-Connecting-IP') || 
         request.headers.get('X-Forwarded-For') || 
         'unknown';
}

const BLOCKED_IPS = new Set([
  '192.168.1.100',
  '10.0.0.50'
]);

function isBlockedIP(ip) {
  return BLOCKED_IPS.has(ip);
}

// Usage in request handler
const clientIP = getClientIP(request);
if (isBlockedIP(clientIP)) {
  return new Response('Access denied', { status: 403 });
}

🔒 Data Protection

Sensitive Data Handling

Never log sensitive information:

function sanitizeForLogging(data) {
  const sanitized = { ...data };
  
  // Remove sensitive fields
  delete sanitized.api_key;
  delete sanitized.authorization;
  delete sanitized.password;
  
  // Truncate long content
  if (sanitized.messages) {
    sanitized.messages = sanitized.messages.map(msg => ({
      ...msg,
      content: msg.content.length > 100 ? 
        msg.content.substring(0, 100) + '...[truncated]' : 
        msg.content
    }));
  }
  
  return sanitized;
}

// Usage
console.log('Request received:', sanitizeForLogging(requestData));

Response Sanitization

Clean responses before sending:

function sanitizeResponse(response) {
  // Remove internal fields
  const sanitized = { ...response };
  delete sanitized.internal_id;
  delete sanitized.debug_info;
  delete sanitized.upstream_headers;
  
  return sanitized;
}

🌐 CORS Configuration

Secure CORS Setup

Configure CORS properly:

function setCORSHeaders(response, origin) {
  const allowedOrigins = [
    'https://yourdomain.com',
    'https://app.yourdomain.com',
    'https://localhost:3000' // Development only
  ];
  
  if (allowedOrigins.includes(origin)) {
    response.headers.set('Access-Control-Allow-Origin', origin);
  }
  
  response.headers.set('Access-Control-Allow-Methods', 'POST, OPTIONS');
  response.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  response.headers.set('Access-Control-Max-Age', '86400');
  
  return response;
}

// Handle preflight requests
if (request.method === 'OPTIONS') {
  const origin = request.headers.get('Origin');
  const response = new Response(null, { status: 204 });
  return setCORSHeaders(response, origin);
}

📝 Security Headers

Essential Security Headers

Add security headers to all responses:

function addSecurityHeaders(response) {
  response.headers.set('X-Content-Type-Options', 'nosniff');
  response.headers.set('X-Frame-Options', 'DENY');
  response.headers.set('X-XSS-Protection', '1; mode=block');
  response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
  response.headers.set('Content-Security-Policy', "default-src 'none'");
  
  // Remove server information
  response.headers.delete('Server');
  
  return response;
}

🔍 Security Monitoring

Security Event Logging

Log security-related events:

function logSecurityEvent(event, details) {
  console.warn('Security event:', {
    event,
    timestamp: new Date().toISOString(),
    ...details
  });
  
  // Send to security monitoring service
  if (env.SECURITY_WEBHOOK) {
    fetch(env.SECURITY_WEBHOOK, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        service: 'ai-proxy-worker',
        event,
        timestamp: new Date().toISOString(),
        ...details
      })
    }).catch(err => console.error('Failed to send security alert:', err));
  }
}

// Usage
logSecurityEvent('authentication_failure', {
  ip: getClientIP(request),
  userAgent: request.headers.get('User-Agent'),
  path: new URL(request.url).pathname
});

Anomaly Detection

Detect unusual patterns:

class AnomalyDetector {
  constructor() {
    this.requestPatterns = new Map();
  }
  
  recordRequest(clientId, endpoint) {
    const key = `${clientId}:${endpoint}`;
    const now = Date.now();
    
    if (!this.requestPatterns.has(key)) {
      this.requestPatterns.set(key, []);
    }
    
    const requests = this.requestPatterns.get(key);
    requests.push(now);
    
    // Keep only recent requests (last hour)
    const oneHourAgo = now - 3600000;
    const recentRequests = requests.filter(ts => ts > oneHourAgo);
    this.requestPatterns.set(key, recentRequests);
    
    // Detect anomalies
    if (recentRequests.length > 1000) { // More than 1000 requests per hour
      logSecurityEvent('high_frequency_requests', {
        clientId,
        endpoint,
        requestCount: recentRequests.length
      });
    }
  }
}

🛠️ Environment Configuration

Production Environment Variables

Secure environment setup:

# Required secrets
wrangler secret put DEEPSEEK_API_KEY
wrangler secret put PROXY_KEY

# Optional security settings
wrangler secret put SECURITY_WEBHOOK
wrangler secret put RATE_LIMIT_MAX_REQUESTS
wrangler secret put ALLOWED_ORIGINS

Configuration Validation

Validate environment on startup:

function validateEnvironment(env) {
  const required = ['DEEPSEEK_API_KEY'];
  const missing = required.filter(key => !env[key]);
  
  if (missing.length > 0) {
    throw new Error(`Missing required environment variables: ${missing.join(', ')}`);
  }
  
  // Validate API key format
  if (!env.DEEPSEEK_API_KEY.startsWith('sk-')) {
    console.warn('DEEPSEEK_API_KEY may be invalid - should start with sk-');
  }
  
  return true;
}

🚨 Incident Response

Security Incident Checklist

When a security incident is detected:

  1. Immediate Response

    • Identify the scope of the incident
    • Block malicious traffic if possible
    • Preserve logs and evidence
  2. Assessment

    • Determine what data may have been accessed
    • Assess the impact on users and services
    • Check for ongoing threats
  3. Containment

    • Rotate compromised API keys
    • Update security rules
    • Deploy patches if needed
  4. Recovery

    • Restore normal operations
    • Monitor for continued threats
    • Validate security measures
  5. Post-Incident

    • Document lessons learned
    • Update security procedures
    • Notify stakeholders if required

Emergency Procedures

// Emergency shutdown capability
async function emergencyShutdown(reason) {
  logSecurityEvent('emergency_shutdown', { reason });
  
  // Return maintenance mode response
  return new Response(JSON.stringify({
    error: 'service_unavailable',
    message: 'Service temporarily unavailable for maintenance',
    timestamp: new Date().toISOString()
  }), {
    status: 503,
    headers: {
      'Content-Type': 'application/json',
      'Retry-After': '3600'
    }
  });
}

📋 Security Checklist

Pre-deployment Security Review

  • All API keys stored as secrets
  • Input validation implemented
  • Rate limiting configured
  • CORS properly configured
  • Security headers added
  • Logging sanitized
  • Error messages don't leak information
  • Dependencies updated
  • Security monitoring enabled

Regular Security Maintenance

  • Review access logs monthly
  • Update dependencies quarterly
  • Rotate API keys annually
  • Test incident response procedures
  • Review and update security policies

Security is an ongoing process 🔒

Regular reviews and updates ensure your AI Proxy Worker remains secure against evolving threats.