强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

CDN 与 WAF 精讲教程 / 第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 实战 →