适用场景
API 安全防护适用于以下场景:企业提供 RESTful 或 GraphQL 接口供前端、移动端与第三方系统调用,需要统一认证与权限控制;接口被恶意调用造成流量滥用、刷单或数据爬取;微服务架构中网关与各服务间需要身份传递与限流能力。本文以 JWT 认证与接口限流为主线,提供一套可直接落地的 API 安全防护配置方案。
前置条件
- 一个可运行的 API 服务(本文示例使用 Python 3.9+ 与 FastAPI)
- 已安装依赖:
pip install fastapi uvicorn pyjwt redis - 了解 HTTP 状态码与常见认证头(Authorization)格式
原理说明
API 安全的核心是认证(Authentication)与授权(Authorization)的分离,以及资源保护。JWT(JSON Web Token)是一种无状态令牌,由 Header、Payload、Signature 三段组成,签名保证了令牌不可伪造。相比 Session,JWT 不需要服务端存储会话,天然适合分布式部署,但正因无状态,令牌一旦泄露无法即时吊销,因此必须配合短有效期、HTTPS 传输与密钥轮换。限流(Rate Limiting)则通过令牌桶或滑动窗口算法限制单位时间内的请求次数,防止接口被刷爆或拖垮后端。
操作步骤
1. JWT 签发与校验的正确姿势
# auth.py - JWT 签发与校验
import jwt, datetime
SECRET_KEY = "please-change-this-256bit-secret-key"
ALGORITHM = "HS256"
def create_token(user_id: int) -> str:
payload = {
"sub": str(user_id),
"iat": datetime.datetime.now(datetime.timezone.utc),
"exp": datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(minutes=30),
"scope": ["user:read", "user:write"],
}
return jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM)
def verify_token(token: str) -> dict:
# verify=True 会自动校验签名与 exp
return jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
关键参数:exp 必须设置(建议 30 分钟以内),algorithms 必须显式指定而非接受任意算法,防止算法混淆攻击。
2. 在 FastAPI 中接入认证与限流
# main.py - FastAPI 认证中间件 + Redis 限流
from fastapi import FastAPI, Depends, HTTPException, Header
import redis, time
r = redis.Redis(host="127.0.0.1", port=6379, decode_responses=True)
app = FastAPI()
def rate_limit(client_ip: str, limit: int = 60, window: int = 60):
key = f"rl:{client_ip}:{int(time.time()) // window}"
count = r.incr(key)
if count == 1:
r.expire(key, window)
if count > limit:
raise HTTPException(status_code=429, detail="请求过于频繁,请稍后再试")
@app.get("/api/data")
def get_data(authorization: str = Header(...)):
client_ip = "0.0.0.0" # 生产环境从 X-Forwarded-For 或真实连接获取
rate_limit(client_ip)
token = authorization.replace("Bearer ", "")
try:
payload = verify_token(token)
except jwt.ExpiredSignatureError:
raise HTTPException(status_code=401, detail="令牌已过期")
except jwt.InvalidTokenError:
raise HTTPException(status_code=401, detail="令牌无效")
return {"user": payload["sub"], "data": "sensitive"}
关键参数:limit 与 window 决定限流阈值(示例为 60 秒内 60 次);status_code=429 是标准的限流响应码,客户端据此做退避重试。
3. 密钥管理与轮换
# 生成强随机密钥(256 bit)
openssl rand -base64 32
# 生产环境务必从环境变量或密钥管理服务读取,禁止硬编码
export JWT_SECRET="$(openssl rand -base64 32)"
4. 网关层加固(Nginx 侧)
# 在 Nginx 中为 /api/ 前缀启用 IP 限流,与业务层形成双重防护
limit_req_zone $binary_remote_addr zone=api_zone:10m rate=10r/s;
server {
location /api/ {
limit_req zone=api_zone burst=20 nodelay;
proxy_pass http://backend:8000;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
关键参数:rate=10r/s 为平均速率,burst=20 允许突发峰值,nodelay 让超出突发量的请求立即返回 503/429,避免队列堆积拖垮后端。
5. 常见攻击面封堵
# 1) 校验 Content-Type,拒绝非 JSON 请求
# 2) 输入校验:长度、类型、白名单正则
# 3) 错误信息不泄露内部细节:统一返回 {code, message} 而非堆栈
# 4) 关闭 CORS 通配符,仅允许受信来源
# 5) 日志脱敏:不记录完整令牌与密码字段
配置验证
# 1. 启动服务
uvicorn main:app --host 0.0.0.0 --port 8000
# 2. 获取令牌(假设存在 /api/login 签发接口)
TOKEN=$(curl -s -X POST http://127.0.0.1:8000/api/login -d '{"user":"admin"}' -H "Content-Type: application/json" | python -c "import sys,json;print(json.load(sys.stdin)['token'])")
# 3. 携带令牌访问受保护接口
curl -s http://127.0.0.1:8000/api/data -H "Authorization: Bearer $TOKEN"
# 4. 无令牌访问应返回 401
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8000/api/data
# 期望输出:401
# 5. 限流验证:连续快速请求 70 次,第 61 次后应返回 429
for i in $(seq 1 70); do curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8000/api/data -H "Authorization: Bearer $TOKEN"; done | sort | uniq -c
常见问题
Q1:JWT 被泄露后如何快速止损?
JWT 无状态特性决定了无法在签发端直接吊销,止损三板斧:一是把有效期缩短到 15-30 分钟;二是维护一个 jti(令牌 ID)黑名单缓存(Redis 中存储至令牌过期);三是立即轮换签名密钥,让所有旧令牌全部失效并强制用户重新登录。对于高价值接口,建议引入 Refresh Token 机制,Access Token 有效期短、Refresh Token 可吊销。
Q2:限流应该做在网关还是业务层?
两层都要做,职责不同。网关(Nginx/API 网关)限流基于 IP/UA,挡住大部分 DDoS 与爬虫流量,保护整个后端;业务层限流基于用户维度(user_id/API Key),防止单个合法账号刷接口。两者配合才是完整方案。注意用户限流要放在认证之后,否则无法区分用户。
Q3:GraphQL 接口限流有什么特殊之处?
GraphQL 单次请求可批量查询,仅按请求数限流会被绕过。应额外限制查询复杂度(深度 + 节点数),如限制深度不超过 5、单次查询节点不超过 100,并在网关计算 cost 累加值做配额控制。
总结
API 安全防护的关键是认证、授权、限流与日志四层协同。JWT 用短有效期与显式算法绑定规避无状态令牌的固有风险,Redis 滑动窗口与 Nginx limit_req 分别实现用户维度和 IP 维度的限流,密钥从环境变量/密钥管理服务读取并定期轮换。建议上线前用压测工具(如 ab、wrk)验证限流生效阈值,并将 401/429 的统计接入监控告警。