强曰为道

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

第10章 API 安全

第10章 API 安全

随着微服务和前后端分离架构的普及,API 已成为 Web 应用的核心接口。本章从 CDN/WAF 角度讲解 API 安全的关键技术和最佳实践。


10.1 API 安全威胁全景

10.1.1 OWASP API Security Top 10 (2023)

排名风险说明WAF 防护
API1Broken Object Level Authorization对象级越权(IDOR)参数校验规则
API2Broken Authentication认证缺陷暴力破解防护
API3Broken Object Property Level Authorization属性级越权响应过滤
API4Unrestricted Resource Consumption无限制资源消耗速率限制
API5Broken Function Level Authorization功能级越权路径+方法限制
API6Unrestricted Access to Sensitive Business Flows敏感业务流滥用行为分析
API7Server Side Request Forgery (SSRF)服务端请求伪造出站过滤
API8Security Misconfiguration安全配置错误安全头注入
API9Improper Inventory Management资产管理不足API 发现
API10Unsafe 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简单内部 APIBase64 解码检查
Bearer Token (JWT)中-高移动端/SPAToken 验证
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 实战 →