第10章 API 安全
第10章 API 安全
随着微服务和前后端分离架构的普及,API 已成为 Web 应用的核心接口。本章从 CDN/WAF 角度讲解 API 安全的关键技术和最佳实践。
10.1 API 安全威胁全景
10.1.1 OWASP API Security Top 10 (2023)
| 排名 | 风险 | 说明 | WAF 防护 |
|---|
| API1 | Broken Object Level Authorization | 对象级越权(IDOR) | 参数校验规则 |
| API2 | Broken Authentication | 认证缺陷 | 暴力破解防护 |
| API3 | Broken Object Property Level Authorization | 属性级越权 | 响应过滤 |
| API4 | Unrestricted Resource Consumption | 无限制资源消耗 | 速率限制 |
| API5 | Broken Function Level Authorization | 功能级越权 | 路径+方法限制 |
| API6 | Unrestricted Access to Sensitive Business Flows | 敏感业务流滥用 | 行为分析 |
| API7 | Server Side Request Forgery (SSRF) | 服务端请求伪造 | 出站过滤 |
| API8 | Security Misconfiguration | 安全配置错误 | 安全头注入 |
| API9 | Improper Inventory Management | 资产管理不足 | API 发现 |
| API10 | Unsafe Consumption of APIs | 不安全的第三方 API | 输入验证 |
10.1.2 API 攻击向量
API 攻击向量:
┌─────────────────────────────────────────────────────────┐
│ 认证攻击 │
│ ├── API Key 泄露 / 暴力破解 │
│ ├── JWT Token 伪造 / 过期利用 │
│ ├── OAuth 授权码劫持 │
│ └── 凭证填充 (Credential Stuffing) │
├─────────────────────────────────────────────────────────┤
│ 授权攻击 │
│ ├── IDOR(ID 篡改访问他人资源) │
│ ├── 功能越权(普通用户调用管理员 API) │
│ └── BOLA(对象级授权绕过) │
├─────────────────────────────────────────────────────────┤
│ 输入攻击 │
│ ├── SQL/NoSQL 注入 │
│ ├── XXE (XML External Entity) │
│ ├── 反序列化攻击 │
│ └── SSRF (Server-Side Request Forgery) │
├─────────────────────────────────────────────────────────┤
│ 业务攻击 │
│ ├── 过度调用(资源消耗型攻击) │
│ ├── 批量数据抓取 │
│ ├── 业务逻辑绕过 │
│ └── 自动化欺诈 │
└─────────────────────────────────────────────────────────┘
10.2 速率限制(Rate Limiting)
10.2.1 API 限速策略
| 策略 | 适用场景 | 示例 |
|---|
| 固定窗口 | 一般 API | 每分钟 60 次 |
| 滑动窗口 | 精确限速 | 最近 60 秒内 60 次 |
| 令牌桶 | 允许突发 | 每秒 10 次,突发 20 次 |
| 按用户 | 登录用户 | 每小时 1000 次 |
| 按 API Key | 开放 API | 免费版 1000/h,付费版 10000/h |
| 全局限流 | 保护后端 | 全站最大 10000 QPS |
10.2.2 API 限速响应标准
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 60
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1715347200
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Please retry after 60 seconds.",
"retry_after": 60
}
}
10.2.3 Nginx API 限速
# 基于 API Key 的限速
http {
# 使用 $http_x_api_key 作为限速键
map $http_x_api_key $api_key_zone {
default "default";
"key-premium-user-123" "premium";
"key-basic-user-456" "basic";
}
limit_req_zone $api_key_zone zone=api_default:10m rate=10r/s;
limit_req_zone $api_key_zone zone=api_premium:10m rate=100r/s;
limit_req_zone $api_key_zone zone=api_basic:10m rate=30r/s;
server {
location /api/v1/ {
# 不同套餐使用不同限速
limit_req zone=api_default burst=20 nodelay;
# 按 $api_key_zone 变量选择限速策略
if ($api_key_zone = "premium") {
# 使用 premium 限速(通过 map 映射)
}
add_header X-RateLimit-Limit "${limit_req_limit}" always;
add_header X-RateLimit-Remaining "${limit_req_remaining}" always;
}
}
}
10.3 输入验证
10.3.1 API 输入验证清单
| 验证项 | 说明 | 示例 |
|---|
| 类型验证 | 参数类型检查 | id 必须是整数 |
| 长度验证 | 字符串长度限制 | username 3-32 字符 |
| 范围验证 | 数值范围 | page 1-1000 |
| 格式验证 | 正则匹配 | email 格式、手机号格式 |
| 枚举验证 | 限定取值 | status 只能是 active/inactive |
| 编码验证 | 特殊字符转义 | 防止 XSS/SQL 注入 |
| 内容验证 | 文件类型/大小 | 上传文件仅允许 jpg/png/pdf |
10.3.2 WAF 输入验证规则
# API 输入验证规则示例
# 1. ID 参数必须为纯数字
SecRule ARGS:id "!@rx ^\d+$" \
"id:11001,phase:2,block,msg:'API ID parameter must be numeric'"
# 2. Email 格式验证
SecRule ARGS:email "!@rx ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$" \
"id:11002,phase:2,block,msg:'Invalid email format'"
# 3. JSON Body 大小限制
SecRule REQUEST_HEADERS:Content-Length "@gt 1048576" \
"id:11003,phase:1,block,msg:'Request body too large (>1MB)'"
# 4. Content-Type 白名单
SecRule REQUEST_METHOD "@rx ^(POST|PUT|PATCH)$" \
"id:11004,phase:1,chain,block,msg:'Invalid Content-Type'"
SecRule REQUEST_HEADERS:Content-Type "!@rx ^(application/json|multipart/form-data)$" ""
# 5. 特殊字符检测(防注入)
SecRule ARGS "@rx [;|`$]" \
"id:11005,phase:2,block,msg:'Special characters not allowed in parameters'"
10.4 认证与授权
10.4.1 API 认证方式对比
| 方式 | 安全性 | 适用场景 | CDN/WAF 验证 |
|---|
| API Key | 低 | 公开 API、监控 | Header 检查 |
| Basic Auth | 低 | 简单内部 API | Base64 解码检查 |
| Bearer Token (JWT) | 中-高 | 移动端/SPA | Token 验证 |
| OAuth 2.0 | 高 | 第三方授权 | Token 验证 |
| mTLS | 最高 | 服务间通信 | 证书验证 |
| HMAC 签名 | 高 | Webhook 回调 | 签名验证 |
10.4.2 JWT 验证(边缘层)
// Cloudflare Workers JWT 验证
export default {
async fetch(request) {
const authHeader = request.headers.get('Authorization');
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return new Response(JSON.stringify({ error: 'Missing token' }), {
status: 401,
headers: { 'Content-Type': 'application/json' }
});
}
const token = authHeader.slice(7);
try {
// 使用 Web Crypto API 验证 JWT
const payload = await verifyJWT(token, SECRET_KEY);
// 检查 Token 过期
if (payload.exp && payload.exp < Math.floor(Date.now() / 1000)) {
return new Response(JSON.stringify({ error: 'Token expired' }), {
status: 401,
headers: { 'Content-Type': 'application/json' }
});
}
// 将用户信息注入到上游请求头
const headers = new Headers(request.headers);
headers.set('X-User-Id', payload.sub);
headers.set('X-User-Role', payload.role || 'user');
return fetch(new Request(request, { headers }));
} catch (e) {
return new Response(JSON.stringify({ error: 'Invalid token' }), {
status: 401,
headers: { 'Content-Type': 'application/json' }
});
}
}
}
10.4.3 OAuth 2.0 流程
OAuth 2.0 Authorization Code Flow:
┌──────────┐ ┌─────────────┐ ┌──────────┐
│ Client │ │ Auth Server │ │ Resource │
│ (SPA/App) │ │ │ │ Server │
└─────┬────┘ └──────┬──────┘ └────┬─────┘
│ │ │
│ 1. 用户点击登录 │ │
│ ──→ 重定向到授权端点 │ │
│ │ │
│ 2. 用户授权 │ │
│ ←── 返回授权码 (code) │ │
│ │ │
│ 3. 用 code 换 Token │ │
│ ──→ POST /token {code, ...} │ │
│ │ │
│ 4. 返回 access_token + refresh_token │
│ ←── {access_token, refresh_token} │ │
│ │ │
│ 5. 使用 access_token 调用 API │ │
│ ──→ GET /api/data (Bearer token) ──────────────────────→ │
│ │ │
│ 6. 返回资源数据 │ │
│ ←── {data: ...} │ │
│ │ │
10.5 API 密钥管理
10.5.1 API Key 安全规范
| 规范 | 说明 |
|---|
| 生成 | 至少 32 字节随机数,Base64 编码 |
| 传输 | 仅通过 HTTPS,使用 Header 而非 URL 参数 |
| 存储 | 服务端存储哈希值,不存储明文 |
| 轮换 | 定期轮换(建议 90 天),支持平滑切换 |
| 权限 | 最小权限原则,Key 绑定具体 API 范围 |
| 吊销 | 支持即时吊销,泄露时快速失效 |
| 审计 | 记录所有 API Key 使用日志 |
10.5.2 API Key 泄露检测
# 扫描 Git 仓库中的 API Key 泄露
# 使用 trufflehog / gitleaks 等工具
# trufflehog 示例
trufflehog git https://github.com/org/repo --only-verified
# GitHub Secret Scanning(自动检测)
# 在 GitHub 仓库设置中启用 Secret Scanning
# 自定义正则扫描
grep -rn -E "(api[_-]?key|secret[_-]?key|access[_-]?token)\s*[:=]\s*['\"][A-Za-z0-9+/=]{20,}" ./src/
10.6 GraphQL 安全
10.6.1 GraphQL 特有威胁
| 威胁 | 说明 | 防护方式 |
|---|
| 查询深度攻击 | 嵌套极深的查询耗尽资源 | 限制最大查询深度(如 10 层) |
| 查询复杂度攻击 | 单次查询请求大量字段 | 计算查询复杂度并设限 |
| 内省查询 | __schema 暴露 API 结构 | 生产环境禁用内省 |
| 批量查询 | 单次请求多个操作 | 限制单次操作数量 |
| 字段建议泄露 | 错误信息暴露字段名 | 禁用字段建议 |
10.6.2 GraphQL 安全配置
// GraphQL 安全配置(Node.js / Apollo Server 示例)
const { ApolloServer } = require('@apollo/server');
const server = new ApolloServer({
typeDefs,
resolvers,
// 安全配置
validationRules: [
// 限制查询深度
createDepthLimitRule(10),
// 限制查询复杂度
createComplexityRule({
maximumComplexity: 1000,
estimators: [
fieldExtensionsEstimator(),
simpleEstimator({ defaultComplexity: 1 })
]
}),
// 禁用内省(生产环境)
NoIntrospection(),
],
// 限制单次操作数量
allowBatchedHttpRequests: false,
// 格式化错误(不暴露内部信息)
formatError: (error) => {
if (error.extensions?.code === 'GRAPHQL_VALIDATION_FAILED') {
return { message: 'Invalid query' };
}
return { message: 'Internal server error' };
},
});
10.6.3 WAF GraphQL 规则
# ModSecurity GraphQL 安全规则
# 限制请求体大小(GraphQL 查询可能很大)
SecRule REQUEST_BODY "@gt 51200" \
"id:12001,phase:2,block,msg:'GraphQL query too large (>50KB)'"
# 检测内省查询
SecRule REQUEST_BODY "@rx __schema|__type" \
"id:12002,phase:2,block,msg:'GraphQL introspection blocked'"
# 检测批量查询
SecRule REQUEST_BODY "@rx \[.*query.*mutation" \
"id:12003,phase:2,block,msg:'Batch GraphQL queries blocked'"
# 检测深层嵌套
SecRule REQUEST_BODY "@rx (\{[^}]{0,100}){8,}" \
"id:12004,phase:2,block,msg:'GraphQL query depth exceeded'"
10.7 API 网关安全架构
API 安全分层架构:
客户端
│
▼
┌──────────────────────────────────────────────────────────────┐
│ CDN / 边缘层 │
│ ├── TLS 终结 │
│ ├── DDoS 防护 │
│ ├── Bot 检测 │
│ ├── 地理限制 │
│ └── 基础 WAF │
└───────────────────────┬──────────────────────────────────────┘
│
┌───────────────────────▼──────────────────────────────────────┐
│ API Gateway │
│ ├── 认证验证(JWT/OAuth) │
│ ├── 速率限制 │
│ ├── 请求转换 │
│ ├── API 版本路由 │
│ └── 日志审计 │
└───────────────────────┬──────────────────────────────────────┘
│
┌───────────────────────▼──────────────────────────────────────┐
│ 服务层 │
│ ├── 业务授权(RBAC/ABAC) │
│ ├── 输入验证 │
│ ├── 业务逻辑 │
│ └── 数据访问 │
└──────────────────────────────────────────────────────────────┘
10.8 注意事项
⚠️ API 发现:维护完整的 API 清单,包括未公开的"影子 API"。未管理的 API 是最大安全盲区。
⚠️ 版本管理:旧版本 API 可能存在已知漏洞,应设定下线时间表。
⚠️ 错误信息:API 错误响应不应暴露内部实现细节(如数据库结构、堆栈跟踪)。
⚠️ CORS 配置:Access-Control-Allow-Origin: * 在生产环境中是危险的,应使用精确域名白名单。
10.9 扩展阅读
本章小结
| 主题 | 核心要点 |
|---|
| API 威胁 | OWASP API Top 10,IDOR/认证/资源消耗 |
| 速率限制 | 多维度限速(IP/Key/User/API),返回标准头 |
| 输入验证 | 类型/长度/格式/编码多层验证 |
| 认证 | JWT 边缘验证,OAuth 2.0 标准授权流程 |
| GraphQL | 限制查询深度/复杂度,禁用内省 |
下一章:第11章 Cloudflare 实战 →