正在加载,请稍候…

API Security: OWASP API Top 10 and Modern Defense Patterns

Protect your APIs against OWASP API Top 10. Covers broken object authorization, mass assignment, SQL injection, rate limiting, security headers, and JWT best practices.

API Security: OWASP API Top 10

APIs are the primary attack surface of modern applications. Here are defenses against the most critical vulnerabilities.

1. Broken Object Level Authorization (BOLA)

// VULNERABLE: No ownership check
app.get('/api/orders/:id', async (req, res) => {
  const order = await Order.findById(req.params.id);
  res.json(order); // Any user can access any order!
});

// SECURE: Verify the user owns the resource
app.get('/api/orders/:id', authenticate, async (req, res) => {
  const order = await Order.findOne({
    _id: req.params.id,
    userId: req.user.id, // Ownership check
  });
  if (!order) return res.status(404).json({ error: 'Not found' });
  res.json(order);
});

2. Broken Authentication

import rateLimit from 'express-rate-limit';

const loginLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 5, // 5 attempts per 15 minutes
  message: 'Too many login attempts, try again later',
  skipSuccessfulRequests: true,
});

app.post('/api/login', loginLimiter, async (req, res) => {
  const { email, password } = req.body;
  const user = await User.findOne({ email });
  if (!user || !await bcrypt.compare(password, user.passwordHash)) {
    return res.status(401).json({ error: 'Invalid credentials' });
  }
  const token = jwt.sign({ id: user.id }, process.env.JWT_SECRET, { expiresIn: '15m' });
  res.json({ token });
});

3. Mass Assignment Prevention

// VULNERABLE: User can set isAdmin: true
app.put('/api/users/:id', async (req, res) => {
  await User.findByIdAndUpdate(req.params.id, req.body); // DANGEROUS
});

// SECURE: Whitelist allowed fields
const ALLOWED_FIELDS = ['name', 'email', 'bio', 'avatar'];

app.put('/api/users/:id', authenticate, async (req, res) => {
  const updates = Object.keys(req.body)
    .filter(key => ALLOWED_FIELDS.includes(key))
    .reduce((obj, key) => ({ ...obj, [key]: req.body[key] }), {});
  await User.findByIdAndUpdate(req.params.id, { $set: updates });
  res.json({ success: true });
});

4. SQL Injection Prevention

// VULNERABLE
const result = await db.query(`SELECT * FROM users WHERE name = '${name}'`);

// SECURE: Parameterized queries
const result = await db.query('SELECT * FROM users WHERE name = $1', [name]);

// SECURE: Validate input with Zod
import { z } from 'zod';
const searchSchema = z.object({
  q: z.string().max(100).regex(/^[a-zA-Z0-9 ]+$/),
  limit: z.number().int().min(1).max(100).default(20),
});

app.get('/api/search', (req, res) => {
  const params = searchSchema.parse(req.query); // Throws if invalid
  // Use params safely
});

5. Security Headers

import helmet from 'helmet';

app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'"],
      styleSrc: ["'self'", "'unsafe-inline'"],
    },
  },
  hsts: { maxAge: 31536000, includeSubDomains: true, preload: true },
  referrerPolicy: { policy: 'same-origin' },
}));

app.use(cors({
  origin: ['https://myapp.com'],
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
}));
app.disable('x-powered-by');

6. Rate Limiting Per User

import { RateLimiterRedis } from 'rate-limiter-flexible';

const apiLimiter = new RateLimiterRedis({
  storeClient: redisClient,
  points: 100,      // requests
  duration: 60,     // per 60 seconds per user
  blockDuration: 60,
});

const rateLimitMiddleware = async (req: Request, res: Response, next: NextFunction) => {
  try {
    await apiLimiter.consume(req.user?.id || req.ip);
    next();
  } catch {
    res.status(429).json({ error: 'Too many requests', retryAfter: 60 });
  }
};

7. JWT Best Practices

// Short-lived access tokens + refresh tokens
const accessToken = jwt.sign(
  { id: user.id, role: user.role },
  process.env.JWT_SECRET,
  { expiresIn: '15m', issuer: 'myapi.com', algorithm: 'HS256' }
);

const refreshToken = jwt.sign(
  { id: user.id, type: 'refresh' },
  process.env.REFRESH_SECRET,
  { expiresIn: '7d' }
);

// Store refresh token hash in DB for revocation
await db.refreshTokens.create({
  userId: user.id,
  tokenHash: crypto.createHash('sha256').update(refreshToken).digest('hex'),
  expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
});

Security Testing Checklist

  • Test BOLA: Can user A access user B resources?
  • Test mass assignment: Can user set admin fields?
  • Test injection: SQL, NoSQL, command injection
  • Test rate limiting: Can you brute-force login?
  • Check security headers: securityheaders.com
  • Test JWT: expired, wrong signature, algorithm confusion
  • Run OWASP ZAP or Burp Suite automated scan

Summary

API security is layered defense:

  • Always check object ownership (BOLA)
  • Rate limit authentication endpoints
  • Whitelist allowed fields for updates
  • Use parameterized queries exclusively
  • Set security headers with Helmet
  • Use short-lived JWTs with refresh tokens
  • Validate all input with a schema library