深色模式
API 安全:鉴权、限流与审计
摘要:API 事故集中在三类:鉴权缺失(越权)、无限制(被刷爆)、无审计(出事查不出)。本文给出 Nginx 网关层限流、JWT 校验要点、越权测试方法与审计字段规范。
适用环境
bash
cat /etc/os-release
nginx -v 2>/dev/null || echo "无 nginx"
command -v curl && curl --version | head -1
command -v jq && jq --version
command -v kubectl && kubectl version --short 2>/dev/null1
2
3
4
5
2
3
4
5
操作步骤
1. 先分清认证与授权
- 认证(Authentication):你是谁 —— token 是否有效。
- 授权(Authorization):你能不能操作这个资源 —— 极易被忽略的越权点。
常见漏洞:token 有效就放行,但不校验该 token 对应的用户是否有权访问 user_id=123 的数据(IDOR/水平越权)。
2. JWT 校验要点
bash
# 解码查看 claims(不校验签名,仅查看)
echo "$TOKEN" | cut -d. -f2 | base64 -d 2>/dev/null | jq .1
2
2
服务端必须校验:
- 签名算法固定为预期值,拒绝
alg: none。 exp(过期)、nbf、iat时间窗口。iss(签发者)、aud(受众)。- 密钥轮换时的
kid处理。 - 令牌吊销列表/短 TTL + 刷新机制。
接受 alg: none 或同时接受 HS256/RS256 会导致签名绕过
服务端必须硬编码期望的算法,不信任 token 头部声明的算法。
3. 网关层限流(Nginx)
nginx
# http 段:按客户端 IP 限流
limit_req_zone $binary_remote_addr zone=api_ip:10m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=conn_ip:10m;
# 按用户(从 JWT 或 header 提取)限流
map $http_authorization $api_user {
default "";
"~Bearer .+" $http_x_user_id;
}
limit_req_zone $api_user zone=api_user:10m rate=60r/m;
server {
location /api/ {
limit_req zone=api_ip burst=20 nodelay;
limit_req zone=api_user burst=10 nodelay;
limit_conn conn_ip 50;
limit_req_status 429;
proxy_pass http://api_backend;
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
bash
nginx -t && systemctl reload nginx
# 压测验证
for i in $(seq 1 50); do curl -s -o /dev/null -w '%{http_code}\n' https://api.example.com/api/ping; done | sort | uniq -c1
2
3
2
3
4. 强制 HTTPS 与安全响应头
nginx
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "no-referrer" always;
add_header Content-Security-Policy "default-src 'self'" always;
server {
listen 80;
return 301 https://$host$request_uri;
}1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
5. 输入校验与防滥用
- 所有参数做类型、长度、范围校验(服务端为准,前端校验不算)。
- 分页必须有上限(
limit <= 100),防大查询打爆数据库。 - 上传限制大小与类型,且不在 Web 目录执行。
- 批量接口限制单次条数。
nginx
client_max_body_size 10m;
location /api/ {
if ($request_method !~ ^(GET|POST|PUT|DELETE|PATCH)$ ) { return 405; }
proxy_pass http://api_backend;
}1
2
3
4
5
2
3
4
5
6. 审计日志:每条写操作都要留痕
建议字段:
json
{
"ts": "2026-10-09T10:00:00+08:00",
"request_id": "req-abc123",
"actor": "user:10086",
"actor_ip": "203.0.113.5",
"action": "order.refund",
"resource": "order/123456",
"result": "success",
"user_agent": "Mozilla/5.0 ...",
"latency_ms": 42
}1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
关键要求:
request_id贯穿网关与应用日志,便于串联。- 敏感字段脱敏(手机号、身份证、口令、token 绝不落日志)。
- 写操作(POST/PUT/DELETE)必记,读操作按敏感级别记。
- 日志实时送到集中日志平台。
bash
# 检查日志里是否泄漏敏感信息
grep -rInE '(password|token|id_card|phone)\s*[:=]' /var/log/api/ 2>/dev/null | head -101
2
2
7. 越权自查:手工测试两招
bash
# 1) 水平越权:换别人的资源 ID
curl -s -H "Authorization: Bearer $TOKEN_A" https://api.example.com/api/orders/10001
curl -s -H "Authorization: Bearer $TOKEN_B" https://api.example.com/api/orders/10001
# 两者不应返回相同数据(除非是共享资源)
# 2) 垂直越权:普通用户调管理员接口
curl -s -o /dev/null -w '%{http_code}\n' -H "Authorization: Bearer $TOKEN_USER" \
https://api.example.com/api/admin/users
# 期望 4031
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
8. 接口清单与文档治理
bash
# 枚举现存路由(示例:从网关配置提取)
grep -rhoE 'location [^ {]+' /etc/nginx/conf.d/*.conf | sort -u
# 找出无鉴权的路径(应逐一确认)
grep -rn "auth_request off\|satisfy any" /etc/nginx/conf.d/ 2>/dev/null1
2
3
4
2
3
4
维护一份接口清单:路径、方法、鉴权方式、限流阈值、负责人。未登记的接口一律下线。
验证
bash
# 限流生效
for i in $(seq 1 40); do curl -s -o /dev/null -w '%{http_code} ' https://api.example.com/api/ping; done; echo
# 应有 429 出现
# 无 token 应 401
curl -s -o /dev/null -w '%{http_code}\n' https://api.example.com/api/orders
# 过期/篡改 token 应 401
curl -s -o /dev/null -w '%{http_code}\n' -H "Authorization: Bearer xxxxx" https://api.example.com/api/orders
# HSTS 头存在
curl -sI https://api.example.com | grep -i strict-transport1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
判定标准:限流返回 429;无/失效 token 返回 401;越权返回 403;写操作 100% 有审计记录。
常见坑
只在前端做权限判断
前端隐藏按钮不影响接口可调用。所有鉴权必须在服务端完成。
JWT 只校验签名不校验 exp/aud
过期 token 永久有效、跨系统 token 互用。必须完整校验 claims。
限流只按 IP
NAT 出口或代理后所有用户同一 IP,误杀严重;同时攻击者换 IP 即可绕过。应按 IP + 用户 + 接口多维度限流。
审计日志里写了 token 或身份证
日志泄漏比接口漏洞更难发现。上线前必须做敏感字段扫描。
没有 request_id,出事无法串联
网关生成 X-Request-ID 并透传,应用侧统一打印,是排障与审计的基础设施。