AI Skill Library

API Security Hardening

Rate limiting, CORS, input validation, security headers, API key management.

securityapibackend
# API Security Hardening

## Rate limiting
```ts
import rateLimit from 'express-rate-limit'

const limiter = rateLimit({
  windowMs: 60 * 1000,  // 1 minute
  max: 30,              // 30 requests per window
  standardHeaders: true,
  keyGenerator: (req) => req.headers['x-real-ip'] || req.ip,
})
app.use('/api/', limiter)

// Stricter for auth endpoints
const authLimiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 5 })
app.use('/api/auth/login', authLimiter)
```

## CORS
```ts
import cors from 'cors'
app.use(cors({
  origin: ['https://yourdomain.com'],  // never '*' with credentials
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  credentials: true,
  maxAge: 86400,
}))
```

## Input validation (Zod)
```ts
import { z } from 'zod'

const CreateUserSchema = z.object({
  email: z.string().email().max(255),
  name: z.string().min(1).max(100).trim(),
  age: z.number().int().min(0).max(150).optional(),
})

app.post('/api/users', (req, res) => {
  const result = CreateUserSchema.safeParse(req.body)
  if (!result.success) {
    return res.status(400).json({ errors: result.error.flatten() })
  }
  // result.data is typed and validated
})
```

## Security headers
```ts
import helmet from 'helmet'
app.use(helmet())  // sets ~15 security headers

// Or manually in Next.js
const headers = [
  { key: 'X-Content-Type-Options', value: 'nosniff' },
  { key: 'X-Frame-Options', value: 'DENY' },
  { key: 'X-XSS-Protection', value: '0' },  // deprecated, CSP is better
  { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
  { key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' },
]
```

## API key management
```ts
// Hash API keys in DB (treat like passwords)
const hashedKey = crypto.createHash('sha256').update(apiKey).digest('hex')

// Verify
const inputHash = crypto.createHash('sha256').update(req.headers['x-api-key']).digest('hex')
const keyRecord = await db.apiKey.findUnique({ where: { hash: inputHash } })
```

## Error responses
```ts
// NEVER leak internal details
// BAD:  { error: 'ER_NO_SUCH_TABLE: Table users doesn\'t exist' }
// GOOD: { error: 'Internal server error', code: 'INTERNAL_ERROR' }

app.use((err, req, res, next) => {
  console.error(err)  // log internally
  res.status(500).json({ error: 'Internal server error' })
})
```

API: /api/skills/api-security-hardening