正在加载,请稍候…

API 安全:OWASP API Top 10 与现代防御模式

保护你的 API 免受 OWASP API Top 10 攻击,涵盖对象级授权失效、批量赋值、SQL 注入、速率限制、安全标头及 JWT 最佳实践。

API 安全:OWASP API Top 10 与现代防御模式

API 安全:OWASP API Top 10

API 是现代应用的主要攻击面。以下是对最严重漏洞的防御措施。

1. 对象级授权失效(BOLA)

// 有漏洞:未检查所有权
app.get('/api/orders/:id', async (req, res) => {
  const order = await Order.findById(req.params.id);
  res.json(order); // 任何用户都能访问任何订单!
});

// 安全:验证用户拥有该资源
app.get('/api/orders/:id', authenticate, async (req, res) => {
  const order = await Order.findOne({
    _id: req.params.id,
    userId: req.user.id, // 所有权检查
  });
  if (!order) return res.status(404).json({ error: 'Not found' });
  res.json(order);
});

API 安全:OWASP API Top 10 与现代防御模式 插图

2. 认证失效

import rateLimit from 'express-rate-limit';

const loginLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 5, // 每15分钟5次尝试
  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. 批量赋值防护

// 有漏洞:用户可以设置 isAdmin: true
app.put('/api/users/:id', async (req, res) => {
  await User.findByIdAndUpdate(req.params.id, req.body); // 危险
});

// 安全:白名单允许的字段
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 });
});

API 安全:OWASP API Top 10 与现代防御模式 插图

4. SQL 注入防护

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

// 安全:参数化查询
const result = await db.query('SELECT * FROM users WHERE name = $1', [name]);

// 安全:使用 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); // 无效则抛出异常
  // 安全使用 params
});

5. 安全标头

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');

API 安全:OWASP API Top 10 与现代防御模式 插图

6. 按用户速率限制

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

const apiLimiter = new RateLimiterRedis({
  storeClient: redisClient,
  points: 100,      // 请求数
  duration: 60,     // 每60秒每用户
  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 最佳实践

// 短生命周期访问令牌 + 刷新令牌
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' }
);

// 在数据库中存储刷新令牌的哈希以便撤销
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),
});

安全测试清单

  • 测试 BOLA:用户 A 能否访问用户 B 的资源?
  • 测试批量赋值:用户能否设置管理员字段?
  • 测试注入:SQL、NoSQL、命令注入
  • 测试速率限制:能否暴力破解登录?
  • 检查安全标头:securityheaders.com
  • 测试 JWT:过期、错误签名、算法混淆
  • 运行 OWASP ZAP 或 Burp Suite 自动化扫描

总结

API 安全是分层防御:

  • 始终检查对象所有权(BOLA)
  • 对认证端点进行速率限制
  • 白名单允许更新的字段
  • 仅使用参数化查询
  • 使用 Helmet 设置安全标头
  • 使用短生命周期的 JWT 和刷新令牌
  • 使用模式库验证所有输入