← back to Handbag Auth Nextjs

src/lib/securityHeaders.ts

64 lines

// Security Headers Middleware
// Protects against common web vulnerabilities

export function addSecurityHeaders(response: Response): void {
  const headers = response.headers

  // Prevent clickjacking attacks
  headers.set('X-Frame-Options', 'DENY')

  // Prevent MIME-type sniffing
  headers.set('X-Content-Type-Options', 'nosniff')

  // Enable XSS protection in older browsers
  headers.set('X-XSS-Protection', '1; mode=block')

  // Referrer policy - only send origin on cross-origin requests
  headers.set('Referrer-Policy', 'strict-origin-when-cross-origin')

  // Permissions policy - disable unnecessary features
  headers.set('Permissions-Policy', 'geolocation=(), microphone=(), camera=()')

  // Content Security Policy - prevent XSS and injection attacks
  const csp = [
    "default-src 'self'",
    "script-src 'self' 'unsafe-inline' 'unsafe-eval'",  // Next.js requires unsafe-inline/eval
    "style-src 'self' 'unsafe-inline'",  // Tailwind requires unsafe-inline
    "img-src 'self' data: https: http:",  // Allow external images (Yahoo Japan, etc.)
    "font-src 'self' data:",
    "connect-src 'self'",
    "frame-ancestors 'none'",
    "base-uri 'self'",
    "form-action 'self'"
  ].join('; ')

  headers.set('Content-Security-Policy', csp)

  // Strict Transport Security - force HTTPS (only in production)
  if (process.env.NODE_ENV === 'production') {
    headers.set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains')
  }
}

/**
 * CORS headers for API endpoints
 */
export function addCorsHeaders(response: Response, origin?: string): void {
  const headers = response.headers

  // In production, restrict to specific origins
  const allowedOrigins = process.env.ALLOWED_ORIGINS?.split(',') || ['*']

  if (origin && allowedOrigins.includes('*')) {
    headers.set('Access-Control-Allow-Origin', origin)
  } else if (origin && allowedOrigins.includes(origin)) {
    headers.set('Access-Control-Allow-Origin', origin)
  } else {
    headers.set('Access-Control-Allow-Origin', allowedOrigins[0])
  }

  headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
  headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization')
  headers.set('Access-Control-Max-Age', '86400')  // 24 hours
}