OWASP API Top 10 Prevention
1. Broken Object Authorization
// Always scope queries to the authenticated user
app.get('/orders/:id', auth, async (req, res) => {
const order = await db.order.findFirst({
where: { id: req.params.id, userId: req.user.id }
})
if (!order) return res.status(404).json({ error: 'Not found' })
return res.json(order)
})
2. Input Validation
import { z } from 'zod'
const Schema = z.object({
title: z.string().min(1).max(200).trim(),
tags: z.array(z.string().max(50)).max(10).default([]),
})
app.post('/posts', auth, async (req, res) => {
const result = Schema.safeParse(req.body)
if (!result.success) return res.status(400).json({ errors: result.error.flatten() })
return res.status(201).json(await db.post.create({ data: result.data }))
})
3. Rate Limiting + Security Headers
import helmet from 'helmet'
import rateLimit from 'express-rate-limit'
app.use(helmet({ hsts: { maxAge: 31536000, includeSubDomains: true, preload: true } }))
app.use('/api/', rateLimit({
windowMs: 15 * 60 * 1000, max: 100,
keyGenerator: (req) => req.user?.id ?? req.ip,
}))
app.use('/api/auth/', rateLimit({ windowMs: 3600_000, max: 10 }))
4. SQL Injection
// Always use parameterized queries or ORM
await db.query('SELECT * FROM users WHERE email = $1', [email])
// ORM (Prisma/TypeORM): safe by default
const user = await db.user.findFirst({ where: { email } })
5. Least Privilege Data Exposure
const user = await db.user.findUnique({
where: { id },
select: { id: true, email: true, name: true }
// password, ssn, creditCard: never selected
})
-> Generate tokens with the Token Generator.