🔐 API 安全威胁分析
API 是现代应用的核心,但也是主要攻击面。根据 OWASP API Security Top 10,主要威胁包括:
🎯 核心威胁
- broken Object Level Authorization:越权访问
- broken Authentication:认证绕过
- Excessive Data Exposure:数据过度暴露
- Lack of Resources & Rate Limiting:资源耗尽攻击
- Broken Function Level Authorization:功能级越权
💡 关键数据
根据 Salt Security 2023 报告,94% 的组织在过去一年中经历了 API 安全事件,平均每次事件造成 $3.8M 的损失。
🔑 认证机制设计
认证是 API 安全的第一道防线。我们对比几种主流认证方案:
| 认证方案 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|
| Session + Cookie | 简单、传统 | 不适合分布式、移动端 | 传统 Web 应用 |
| JWT | 无状态、可扩展 | 令牌无法撤销 | SP A、移动端 |
| OAuth 2.0 | delegated 授权 | 复杂、实现成本高 | 第三方登录、授权 |
| API Key | 简单、快速 | 安全性低 | 内部 API、低风险场景 |
JWT 最佳实践
✅ 正确的 JWT 使用方式
// 使用 HttpOnly Cookie 存储 JWT
res.cookie('token', jwt, {
httpOnly: true,
secure: true, // HTTPS
sameSite: 'strict',
maxAge: 360000 // 1小时
})
// 使用短有效期 + 刷新令牌
const accessToken = jwt.sign(payload, secret, { expiresIn: '15m' })
const refreshToken = jwt.sign(payload, secret, { expiresIn: '7d' })⚠️ 常见错误
永远不要将 JWT 存储在 localStorage 或 sessionStorage 中,这会使你容易受到 XSS 攻击。
🔒 HTTPS 与数据传输安全
所有 API 通信必须使用 HTTPS。但需要正确的配置才能确保安全。
TLS 配置最佳实践
禁用不安全的协议
禁用 TLS 1.0 和 1.1,只支持 TLS 1.2 和 1.3。
使用强加密套件
优先使用 ECDHE + AES-GCM 或 ChaCha20-Poly1305。
启用 HSTS
强制客户端使用 HTTPS 连接。
Nginx TLS 配置示例
server {
listen 443 ssl http2;
server_name api.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# 只支持 TLS 1.2 和 1.3
ssl_protocols TLSv1.2 TLSv1.3;
# 强加密套件
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers on;
# HSTS
add_header Strict-Transport-Security "max-age=63072000" always;
# ... 其他配置
}⏱️ 速率限制与防刷
速率限制是防止 API 被滥用的关键措施。它可以防止暴力破解、DDoS、资源耗尽攻击。
速率限制策略
🎯 基于 IP
限制每个 IP 地址的请求频率。简单但容易被绕过(使用代理池)。
👤 基于用户
限制每个用户的请求频率。需要认证,更准确。
🔑 基于 API Key
限制每个 API Key 的请求频率。适合开放 API。
使用 Redis 实现速率限制
const rateLimit = require('express-rate-limit')
const RedisStore = require('rate-limit-redis')
const limiter = rateLimit({
store: new RedisStore({
client: redisClient,
expiry: 60 // 1分钟
}),
windowMs: 60 * 1000, // 1分钟
max: 100, // 最多100次请求
message: 'Too many requests, please try again later.'
})
app.use('/api/', limiter)💡 进阶技巧
对于敏感接口(如登录、注册),应该使用更严格的速率限制,并结合验证码(reCAPTCHA)来防止自动化攻击。
💉 注入攻击防护
注入攻击是最常见的安全漏洞之一。我们需要防止 SQL 注入、NoSQL 注入、命令注入等。
SQL 注入防护
❌ 错误示例(拼接 SQL)
// 攻击者可以输入:' OR '1'='1
const query = `SELECT * FROM users WHERE username = '${username}' AND password = '${password}'`
db.query(query)✅ 正确示例(参数化查询)
// 使用参数化查询
const query = 'SELECT * FROM users WHERE username = ? AND password = ?'
db.query(query, [username, password])
// 或使用 ORM(如 Sequelize)
const user = await User.findOne({
where: { username, password }
})NoSQL 注入防护
❌ 错误示例(MongoDB)
// 攻击者可以输入:{"$gt": ""}
const user = await User.findOne({ username })✅ 正确示例
// 验证输入是字符串
if (typeof username !== 'string') {
return res.status(400).json({ error: 'Invalid input' })
}
const user = await User.findOne({ username: String(username) })✅ API 安全最佳实践
除了上述具体措施,还有一些通用的 API 安全最佳实践:
输入验证
永远不要信任用户输入。使用 JSON Schema、Joi、express-validator 等工具验证所有输入。
输出编码
对所有输出进行编码,防止 XSS 攻击。使用 helmet 等中间件自动设置安全头。
错误处理
不要向客户端返回详细的错误信息(如堆栈跟踪)。使用通用错误响应。
日志记录
记录所有关键操作(登录、敏感数据访问等),但不要在日志中记录敏感信息(如密码、令牌)。
安全头
使用 Helmet 中间件设置安全头:Content-Security-Policy、X-Frame-Options、X-Content-Type-Options 等。
使用 Helmet 设置安全头
const helmet = require('helmet')
app.use(helmet())
// 或自定义配置
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"]
}
}
}))📝 总结
API 安全是一个系统工程,需要从多个层面进行防护:
核心要点
- 认证:使用 JWT + HttpOnly Cookie,短有效期 + 刷新令牌
- 授权:实现 RBAC,检查对象级权限
- 传输安全:强制 HTTPS,正确配置 TLS
- 速率限制:防止滥用和 DDoS
- 注入防护:使用参数化查询,验证所有输入
- 安全头:使用 Helmet 设置安全头
- 日志记录:记录关键操作,但不记录敏感信息
安全不是一次性的工作,而是持续的过程。定期审计、渗透测试、保持依赖更新,才能确保 API 的长期安全。