【Web安全】API安全测试实战指南(OWASP API Top 10全覆盖,保姆级教程)
前言
API(Application Programming Interface)是现代应用的核心,RESTful API和GraphQL API无处不在。从移动端App到单页Web应用,从微服务架构到第三方集成,API已经成为了数字世界的"血管"。随着API的爆发式增长,API安全问题日益突出。2023年OWASP发布了API Security Top 10(2023版),API安全已正式成为独立的安全领域,与传统的Web应用安全(OWASP Top 10)并列。
API安全的紧迫性体现在以下几个方面:第一,API暴露面大,每个端点都是一个潜在的攻击入口,现代微服务架构下API数量动辄成百上千;第二,攻击成本低,许多API漏洞(如BOLA越权)只需修改一个ID参数即可利用,无需复杂漏洞链;第三,数据访问权限高,API直接对接后端数据和业务逻辑,一旦被突破往往造成大规模数据泄露。
【警告】法律免责声明:本文所述技术仅用于授权的安全测试、渗透测试和安全研究。未经授权对他人系统进行API安全测试属于违法行为,可能违反《中华人民共和国网络安全法》《数据安全法》《个人信息保护法》及相关刑法条款。读者应确保在合法授权范围内使用本文知识,作者不对任何滥用行为承担责任。
一、API安全概述
1.1 API分类
在实际安全测试中,我们会遇到多种类型的API,理解它们的特征是做好安全测试的前提。
- RESTful API:基于HTTP动词+资源路径的设计风格,是目前最主流的API形式。它无状态、分层、可缓存,使用JSON或XML作为数据格式。
- GraphQL API:由Facebook提出的单端点查询语言,客户端可以精确指定需要返回的字段。灵活性高,但带来了与传统REST不同的安全挑战。
- SOAP API:基于XML的协议,通常依赖WSDL描述服务接口,企业级应用和金融系统中较多见,常见安全机制是WS-Security。
- gRPC:Google推出的RPC框架,基于HTTP/2和Protobuf序列化,性能高,多用于微服务间内部通信。
| API类型 | 通信格式 | 端点数量 | 安全特点 | 典型场景 |
| --- | --- | --- | --- | --- |
| RESTful | JSON/XML | 多端点 | 基于HTTP语义,授权是重点 | Web/移动应用 |
| GraphQL | JSON | 单端点 | Introspection、深度查询风险 | 复杂数据查询 |
| SOAP | XML | 多端点 | 依赖WS-Security,XML外部实体风险 | 企业集成、金融 |
| gRPC | Protobuf | 多端点 | 内部通信为主,认证与mTLS | 微服务间通信 |
1.2 RESTful API基础
要做好API安全测试,必须先掌握RESTful API的基础语义。
HTTP方法语义:GET用于查询资源(不应有副作用),POST用于创建资源,PUT用于完整更新资源,DELETE用于删除资源,PATCH用于部分更新。在安全测试中,方法篡改(如将GET改为PUT/DELETE)是常见攻击手法。
状态码含义:200表示成功,201表示创建成功,400表示客户端请求错误,401表示未认证,403表示已认证但无权限,404表示资源不存在,500表示服务器内部错误。注意区分401与403,这是授权测试的关键判断点。
认证方式是API安全的基石,常见的认证方式有以下几种:
| 认证方式 | 原理 | 优点 | 缺点 | 安全建议 |
| --- | --- | --- | --- | --- |
| API Key | 静态密钥通过Header传递 | 实现简单 | 易泄露、无法细粒度授权 | 限制权限范围、定期轮换 |
| Bearer Token | 持有Token即代表身份 | 无状态 | Token泄露即完全沦陷 | 短有效期、HTTPS传输 |
| OAuth 2.0 | 授权码换取访问令牌 | 标准化、可委派 | 流程复杂、易实现错误 | 使用PKCE、校验redirect_uri |
| JWT | 签名的JSON声明 | 自包含、跨服务 | 无法主动撤销 | 验证签名算法、设短过期 |
| HMAC签名 | 请求参数+密钥计算签名 | 防篡改、防重放 | 密钥管理复杂 | 时间戳+nonce防重放 |
1.3 OWASP API Security Top 10(2023)概览
OWASP在2023年发布了最新版API安全风险排名,相较于2019版有了较大调整,新增了"敏感业务流程不受限访问""SSRF""API不安全消费"等类别。
| 排名 | 漏洞名称 | 说明 | 风险等级 |
| --- | --- | --- | --- |
| API01:2023 | Broken Object Level Authorization (BOLA) | 对象级授权失效,越权访问他人数据 | 高 |
| API02:2023 | Broken Authentication | 认证机制失效,身份被冒用 | 高 |
| API03:2023 | Broken Object Property Level Authorization | 对象属性级授权失效,过度暴露或批量赋值 | 高 |
| API04:2023 | Unrestricted Resource Consumption | 资源消耗不受限,DoS风险 | 中 |
| API05:2023 | Broken Function Level Authorization (BFLA) | 功能级授权失效,普通用户调用管理功能 | 高 |
| API06:2023 | Unrestricted Access to Sensitive Business Flows | 敏感业务流程不受限,业务逻辑滥用 | 中 |
| API07:2023 | SSRF | 服务端请求伪造,攻击内网 | 高 |
| API08:2023 | Security Misconfiguration | 安全配置错误 | 中 |
| API09:2023 | Improper Inventory Management | 资产清单管理不当,影子API | 中 |
| API10:2023 | Unsafe Consumption of APIs | 不安全地消费第三方API | 中 |
【提示】2023版将BOLA继续列为榜首,说明越权问题依然是API安全中最普遍、危害最大的漏洞类型,测试时应作为重点。
二、API01 - BOLA(对象级授权失效)
2.1 漏洞原理
BOLA(Broken Object Level Authorization,对象级授权失效)是API安全中排名第一的漏洞。其核心问题是:API端点在处理请求时,未验证请求者是否有权访问指定的对象。攻击者只需修改请求中的对象ID(如用户ID、订单ID、文件ID),就能访问到本不属于他的数据。
与传统的水平越权/垂直越权概念对应,BOLA更强调"对象级别"的授权检查缺失。由于RESTful API通过URL路径或参数标识对象(如/api/users/1001),这种漏洞在API中极为常见。
2.2 漏洞代码示例
漏洞代码(Node.js Express直接使用用户输入的ID查询,不校验数据归属):
```javascript
app.get('/api/users/:id/orders', (req, res) => {
const orders = db.query("SELECT * FROM orders WHERE user_id = ?", req.params.id);
res.json(orders);
});
```
上述代码的问题在于:它信任客户端传入的id参数,没有任何校验该id对应的用户是否就是当前登录用户。任何人只要知道或猜出一个user_id,就能查看该用户的全部订单。
安全代码(验证请求者身份与查询对象的归属关系):
```javascript
app.get('/api/users/:id/orders', authenticate, (req, res) => {
// 校验当前登录用户是否有权访问该id的资源
if (req.user.id !== req.params.id && !req.user.isAdmin) {
return res.status(403).json({ error: '禁止访问他人数据' });
}
const orders = db.query("SELECT * FROM orders WHERE user_id = ?", req.params.id);
res.json(orders);
});
```
2.3 实战利用
BOLA的利用手法多样,主要包括以下几种。
水平越权:攻击者以自己的账号登录后,将请求中的ID替换为其他用户的ID。例如正常请求GET /api/users/1001返回自己的资料,修改为GET /api/users/1002即可获取他人资料。如果服务器不做归属校验,就会直接返回他人数据。
垂直越权:普通用户尝试访问本应只有管理员才能调用的接口。例如普通用户发起POST /api/admin/users,如果功能级授权也失效,就可能成功创建用户或执行管理操作(这同时涉及API05 BFLA)。
ID枚举:当对象ID使用自增整数时,攻击者可以遍历ID批量获取数据。从/api/orders/1到/api/orders/100000,用脚本批量请求即可拖库。
关于UUID是否安全:UUID(如550e8400-e29b-41d4-a716-446655440000)相比自增ID大幅降低了遍历风险,因为其空间巨大且不可预测。但UUID并非绝对安全:如果UUID通过日志、URL Referer、前端代码泄露,或者使用了可预测的UUIDv1(含MAC地址和时间戳),攻击者仍可能获取并利用。
2.4 BOLA检测方法
Burp Suite手动测试是检测BOLA最直接的方法。核心思路是用两个不同权限的账号(如A和B),用A的Token请求B的资源,对比响应内容。如果返回的是B的数据而非"禁止访问",则存在BOLA漏洞。
Autorize插件可自动检测越权。配置好低权限账号的Cookie后,插件会自动用低权限身份重放每个请求,对比高低权限的响应是否一致,从而发现越权。
测试Payload示例:
```http
# 水平越权测试:用自己的Token访问他人资源
GET /api/v1/users/1002/profile HTTP/1.1
Host: api.target.com
Authorization: Bearer <user_1001_token>
# 垂直越权测试:普通用户调用管理接口
DELETE /api/admin/users/1001 HTTP/1.1
Host: api.target.com
Authorization: Bearer <normal_user_token>
# ID枚举脚本(Python)
import requests
headers = {"Authorization": "Bearer <token>"}
for uid in range(1, 1000):
r = requests.get(f"https://api.target.com/api/users/{uid}", headers=headers)
if r.status_code == 200:
print(f"[+] Found: {uid} -> {r.json()}")
```
2.5 防御方案
- 对象级授权检查:每个请求都要验证当前用户是否有权访问目标对象,这是BOLA防御的根本。
- 使用当前用户Session中的ID:对于"查询自己的数据"类接口,应从服务端Session/Token中提取用户ID,而非信任客户端传入的ID。
- UUID替代自增ID:使用UUIDv4作为对象标识符,降低枚举遍历的风险(但不可作为唯一防线)。
- 默认拒绝原则:授权检查应默认拒绝,只有明确允许才放行。
三、API02 - 认证失效
3.1 常见认证问题
认证失效是指API的认证机制存在缺陷,导致攻击者可以冒充合法用户身份。常见问题包括以下几类。
弱密码策略:系统不要求密码复杂度、不限制登录失败次数,攻击者可暴力破解或撞库。
Token泄露:Token通过URL参数传递(会被记录在日志、Referer、浏览器历史中),或服务端日志中明文记录了Token。
密码重置漏洞:重置Token可预测(如基于时间戳)、验证码无次数限制可爆破、重置链接发送后不过期。
会话管理缺陷:Token永不过期、注销后Token仍然有效无法撤销、同一账号多处登录无限制。
3.2 API Key泄露
API Key因其实现简单被广泛使用,但静态密钥一旦泄露后果严重。常见泄露位置包括:前端JavaScript代码(直接硬编码)、GitHub仓库(提交时忘记删除)、移动APP反编译后可见、云存储桶公开访问。
检测方法:使用GitHub搜索敏感关键词(如"api_key="、"AKIA");使用jadx工具反编译APK查看反编译代码中的密钥;审计前端JS代码中的硬编码凭证。
```bash
# GitHub搜索泄露的API Key(使用truffleHog工具)
trufflehog github https://github.com/target/repo
# APK反编译查找密钥
jadx -d output/ target.apk
grep -rn "api_key\|secret\|token" output/sources/
```
3.3 防御方案
- 采用OAuth 2.0 + PKCE流程,特别是对公开客户端(SPA、移动端),PKCE可防止授权码截获。
- 使用短期Access Token(如15分钟)配合Refresh Token轮换,降低Token泄露后的影响窗口。
- 关键操作启用多因素认证(MFA)。
- 部署异常登录检测,基于IP、设备指纹、地理位置、行为频率识别异常会话。
- 密码重置Token使用高强度随机数,设置短过期时间,一次性使用。
四、API03 - 对象属性级授权失效
4.1 Mass Assignment(批量赋值漏洞)
Mass Assignment漏洞的原理是:API接收客户端传来的JSON对象后,直接将其映射到后端数据模型并进行更新,没有对字段做白名单过滤。攻击者可以在请求中添加额外字段,修改本不应被修改的属性。
漏洞代码:
```javascript
// 直接将请求体所有字段更新到用户模型,危险
app.put('/api/users/:id', authenticate, (req, res) => {
const user = User.findById(req.params.id);
user.update(req.body); // 批量赋值,未过滤字段
user.save();
res.json(user);
});
```
攻击Payload:攻击者普通注册后,在更新资料的请求中注入role和is_verified字段。
```json
PUT /api/users/1001 HTTP/1.1
Authorization: Bearer <normal_user_token>
Content-Type: application/json
{
"name": "hacker",
"role": "admin",
"is_verified": true,
"balance": 999999
}
```
如果服务端直接将req.body所有字段更新,攻击者就把自己提升为管理员、绕过验证、篡改余额。
4.2 过度数据暴露
过度数据暴露是指API返回了完整的对象,而非客户端所需的最小必要字段,从而暴露了敏感数据。
示例:客户端只需要展示用户名,但API返回了完整对象。
```http
GET /api/users/1001 HTTP/1.1
Host: api.target.com
Authorization: Bearer <token>
# 响应包含了不应暴露的字段
{
"id": 1001,
"name": "test",
"email": "test@example.com",
"password_hash": "$2b$10$xxxxx",
"ssn": "123-45-6789",
"credit_card": "4111111111111111"
}
```
即使password_hash不能逆向,但其泄露仍有助于离线破解;SSN和信用卡号则是直接的敏感信息泄露。
【注意】不要依赖前端"不显示"来保护敏感字段,API响应中的数据对任何抓包者都是可见的,必须在后端做输出过滤。
4.3 防御方案
- 白名单字段更新:只允许特定字段被修改,显式声明可更新字段。
```javascript
// 安全代码:白名单更新
app.put('/api/users/:id', authenticate, (req, res) => {
const allowedFields = ['name', 'avatar']; // 只允许更新这些字段
const updateData = {};
for (const field of allowedFields) {
if (req.body.hasOwnProperty(field)) {
updateData[field] = req.body[field];
}
}
const user = User.findById(req.params.id);
user.update(updateData);
user.save();
res.json(user);
});
```
- 输出过滤(DTO模式):定义数据传输对象,只返回必要字段,不直接序列化整个模型。
```javascript
// 使用DTO只返回必要字段
function userDTO(user) {
return {
id: user.id,
name: user.name,
avatar: user.avatar
// 不返回 password_hash、ssn、credit_card 等
};
}
res.json(userDTO(user));
```
五、API04 - 资源消耗不受限
5.1 漏洞类型
资源消耗不受限是指API未对资源使用做限制,攻击者可通过少量请求消耗大量服务器资源,导致拒绝服务。
无分页或超大分页:GET /api/orders 不带分页参数时返回全部订单,如果数据库有百万条记录,会导致内存溢出(OOM)和数据库慢查询。
文件上传无限制:允许上传超大文件或高频上传,耗尽磁盘存储和带宽。
计算密集型API无限制:复杂查询(如多表关联+全表扫描)、加密运算(如bcrypt成本因子过高)等接口被高频调用。
API调用频率无限制:没有速率限制,攻击者可无限刷接口,消耗服务器CPU、内存、数据库连接池。
5.2 防御方案
分页强制限制:服务端强制分页,并限制最大每页条数(如max page size = 100)。
速率限制(Rate Limiting):在网关层和应用层双重限流。Nginx限流配置示例:
```nginx
# Nginx限流配置:基于IP限制每秒10个请求,突发20个
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
server {
location /api/ {
limit_req zone=api_limit burst=20 nodelay;
proxy_pass http://backend;
}
}
# 限制请求体大小(防大文件上传)
client_max_body_size 10m;
```
Spring Boot应用层限流代码示例(使用Bucket4j):
```java
// Spring Boot 限流示例
@RestController
public class ApiController {
private final Bucket bucket;
public ApiController() {
// 每个用户每分钟最多100次请求
this.bucket = Bucket.builder()
.addLimit(Bandwidth.classic(100, Refill.intervally(100, Duration.ofMinutes(1))))
.build();
}
@GetMapping("/api/data")
public ResponseEntity<?> getData() {
if (bucket.tryConsume(1)) {
return ResponseEntity.ok(service.getData());
}
return ResponseEntity.status(429).body("请求过于频繁,请稍后再试");
}
}
```
此外,还应设置请求体大小限制、计算超时控制(如数据库查询超时30秒)、连接数限制等。
六、API05 - 功能级授权失效(BFLA)
6.1 原理
BFLA(Broken Function Level Authorization)与BOLA的区别在于:BOLA是"对象级"(访问不该访问的数据),BFLA是"功能级"(调用不该调用的功能)。其原理是API未验证用户是否有权调用某功能,导致普通用户可调用管理功能。
6.2 攻击示例
普通用户调用管理接口:攻击者用普通用户Token直接请求管理端点。
```http
# 普通用户尝试删除其他用户
DELETE /api/admin/users/1001 HTTP/1.1
Authorization: Bearer <normal_user_token>
```
HTTP方法篡改:某些实现只在GET方法上做了权限校验,攻击者改用PUT绕过。
```http
# 原本 GET 有权限校验
GET /api/users HTTP/1.1
Authorization: Bearer <normal_user_token>
# 篡改为 PUT 绕过校验,添加管理员
PUT /api/users HTTP/1.1
Authorization: Bearer <normal_user_token>
Content-Type: application/json
{"username": "backdoor", "password": "P@ss1234", "role": "admin"}
```
6.3 防御方案
- RBAC(基于角色的访问控制):为每个API端点定义所需角色,用户必须拥有对应角色才能访问。
- 功能级权限校验中间件:在路由层统一加入权限中间件,避免在每个handler中遗漏校验。
```javascript
// Express 权限中间件示例
function requireRole(role) {
return (req, res, next) => {
if (!req.user || !req.user.roles.includes(role)) {
return res.status(403).json({ error: '权限不足' });
}
next();
};
}
// 管理接口必须 admin 角色
app.delete('/api/admin/users/:id', authenticate, requireRole('admin'), (req, res) => {
// 删除用户逻辑
});
// 默认对所有 /api/admin/* 路径强制要求 admin 角色
app.use('/api/admin/*', authenticate, requireRole('admin'));
```
七、API测试工具与实战
7.1 Postman安全测试
Postman不仅是API调试工具,配合其脚本能力也可做安全测试。
环境变量管理Token:将不同角色的Token存为环境变量(如admin_token、user_token),方便快速切换身份测试越权。
Pre-request Script自动注入Token:在请求前自动从环境变量读取Token并注入Header。
```javascript
// Postman Pre-request Script
const token = pm.environment.get("user_token");
pm.request.headers.add({key: "Authorization", value: "Bearer " + token});
```
Collection Runner批量测试越权:编写一个Collection,遍历多个用户ID,用同一Token请求,检查响应中是否返回了他人数据。配合Tests脚本自动判断:
```javascript
// Postman Tests 脚本:检查是否越权
pm.test("不应返回他人数据", function () {
const responseData = pm.response.json();
pm.expect(responseData.id).to.not.eql(pm.variables.get("expected_other_id"));
});
```
7.2 Burp Suite API测试
Burp Suite是API安全测试的主力工具。可以通过Proxy拦截手工测试,用Repeater重放修改参数,用Intruder批量枚举ID,用Scanner主动扫描API端点。
BApp Store插件推荐:Autorize(自动越权检测)、JWT Editor(JWT编辑与签名攻击)、Param Miner(发现隐藏参数)、HTTP Request Smuggler(请求走私)。
7.3 专用API安全测试工具
| 工具 | 功能 | 适用API类型 | 特点 |
| --- | --- | --- | --- |
| OWASP ZAP | 综合扫描 | REST/SOAP | 开源免费,支持API扫描 |
| Nuclei | 模板化扫描 | REST | YAML模板,社区模板丰富 |
| Kiterunner | 端点发现与爆破 | REST | 大规模API路由爆破 |
| Arjun | 隐藏参数发现 | REST/GraphQL | HTTP参数挖掘 |
| Wfuzz | API Fuzz | REST | 灵活的Fuzz框架 |
| Astra | API安全测试 | REST | 集成扫描与CICD |
Nuclei使用API漏洞检测模板的命令:
```bash
# 使用Nuclei扫描API漏洞(调用官方API相关模板)
nuclei -u https://api.target.com -t ~/nuclei-templates/http/api/
# 批量扫描多个API目标
nuclei -l api_targets.txt -severity high,critical
```
7.4 API文档与端点发现
API端点发现是安全测试的第一步。很多API会暴露文档,直接获取文档能大幅提升测试效率。
Swagger/OpenAPI文档泄露:常见路径如下,直接访问即可获取完整API定义。
```bash
# 常见Swagger/OpenAPI泄露路径
/swagger-ui.html
/swagger-ui/index.html
/api-docs
/v2/api-docs
/v3/api-docs
/openapi.json
/swagger.json
```
从JavaScript文件中提取API端点:前端JS中往往硬编码了API路径,使用LinkFinder工具自动提取。
```bash
# LinkFinder提取JS中的API端点
python3 linkfinder.py -i "https://target.com/*.js" -d -o cli
# 批量提取并去重
python3 linkfinder.py -i "https://target.com" -d -o html > endpoints.html
```
目录爆破发现API端点:使用Kiterunner或ffuf对API路径进行爆破。
```bash
# Kiterunner API端点爆破
kr scan https://api.target.com -w routes-large.kite
# ffuf 爆破API路径
ffuf -u https://api.target.com/api/FUZZ -w api_endpoints.txt -mc 200,201,401,403
# 爆破时带常见API前缀
ffuf -u https://api.target.com/v1/FUZZ -w wordlist.txt -mc all
```
八、GraphQL API安全
8.1 GraphQL基础
GraphQL是一种查询语言,与传统REST的多端点不同,它通常只有一个端点(如/graphql),客户端通过查询语句指定需要返回的字段。
基本操作类型:Query(查询数据,类似GET)、Mutation(变更数据,类似POST/PUT/DELETE)、Subscription(订阅,基于WebSocket实时推送)。
与REST的区别:REST由服务端决定返回哪些字段,GraphQL由客户端决定返回哪些字段;REST多个端点,GraphQL单端点;GraphQL一次请求可获取多个资源,减少请求次数。
8.2 GraphQL安全漏洞
Introspection信息泄露:GraphQL内置自省(Introspection)功能,可查询整个Schema,暴露所有类型和字段,攻击者据此了解全部API结构。
```graphql
# Introspection查询:获取所有类型和字段
{
__schema {
types {
name
fields {
name
type {
name
}
}
}
}
}
```
深度嵌套攻击:利用递归查询构造极深的嵌套结构,导致服务器解析时消耗大量资源,造成DoS。
```graphql
# 恶意深度嵌套查询导致DoS
{
user(id: 1) {
friends {
friends {
friends {
friends {
friends {
friends {
name
}
}
}
}
}
}
}
}
```
批量查询攻击:在单个请求中发送多个查询,绕过基于请求数的速率限制。
```graphql
# 批量查询绕过速率限制
[
{"query": "{ user(id:1) { email } }"},
{"query": "{ user(id:2) { email } }"},
{"query": "{ user(id:3) { email } }"},
{"query": "{ user(id:1000) { email } }"}
]
```
字段建议攻击:GraphQL在字段名错误时会返回建议信息("Did you mean ...?"),攻击者可借此枚举字段名。
```graphql
# 故意输错字段名,触发建议
{
user(id: 1) {
passwrod
}
}
# 响应泄露正确字段名
# "message": "Cannot query field 'passwrod' on type 'User'. Did you mean 'password'?"
```
SQL注入:当GraphQL参数被直接拼接到SQL查询中未做参数化处理时,存在注入风险。
```graphql
# GraphQL参数注入SQL
{
user(name: "admin' UNION SELECT password FROM users--") {
id
email
}
}
```
8.3 GraphQL安全防护
- 生产环境关闭Introspection:禁止查询__schema和__type。
- 查询深度限制:限制最大嵌套深度(如maxDepth = 5)。
- 查询复杂度限制:基于字段计算查询成本,超出阈值拒绝。
- 速率限制:基于查询复杂度而非单纯请求数限流。
- 参数化查询:GraphQL变量使用参数化查询,杜绝拼接。
Apollo Server安全配置示例:
```javascript
// Apollo Server 安全配置
const { ApolloServer } = require('@apollo/server');
const depthLimit = require('graphql-depth-limit');
const { createComplexityLimitRule } = require('graphql-query-complexity');
const server = new ApolloServer({
typeDefs,
resolvers,
validationRules: [
depthLimit(5), // 最大深度5层
createComplexityLimitRule(1000, { // 最大复杂度1000
onCost: (cost) => console.log(`查询成本: ${cost}`),
}),
],
introspection: false, // 生产环境关闭自省
formatError: (err) => {
// 生产环境不返回详细错误信息
if (process.env.NODE_ENV === 'production') {
return { message: 'Internal Server Error' };
}
return err;
},
});
```
九、API安全防护体系
9.1 API网关安全
API网关是所有API请求的统一入口,是实施安全策略的核心位置。
认证与授权:网关层集成OAuth 2.0,统一校验Token有效性,下游服务无需重复实现认证逻辑。
速率限制与配额管理:按用户、按IP、按API维度设置速率限制和调用配额,防止滥用。
请求验证与过滤:在网关层校验请求格式、参数类型、Header合法性,过滤恶意请求。
API版本管理:通过路径版本(/v1/、/v2/)或Header版本管理API版本,便于废弃旧版本和灰度发布。
9.2 WAF for API
传统WAF主要针对Web页面,API专用的WAF需要更精细的防护。
参数校验:校验参数类型(int/string/uuid)、长度范围、格式(正则匹配),拒绝不符合Schema的请求。
注入防护:检测并阻断SQL注入、NoSQL注入(如$gt、$ne操作符)、命令注入。
异常检测:基于行为分析识别异常请求模式,如高频请求、异常参数组合、越权尝试模式。
9.3 API安全监控
日志记录:记录所有API请求(时间、用户、端点、参数、响应状态),但注意不要记录敏感数据(密码、Token)。
异常检测:实时分析日志,检测高频请求(限流绕过尝试)、异常参数(注入特征)、越权尝试(大量403响应)。
API资产清单管理:维护完整的API资产清单,定期扫描发现影子API(未登记的API)和僵尸API(已废弃但仍可访问的API),对应OWASP API09。
9.4 完整防护方案对比
| 防护层 | 措施 | 覆盖的OWASP API Top 10 |
| --- | --- | --- |
| API网关 | 认证授权、限流配额、请求校验 | API01、API02、API04、API05 |
| WAF for API | 参数校验、注入防护、行为分析 | API03、API06、API07 |
| 应用层 | 授权检查、白名单更新、DTO输出 | API01、API03、API05 |
| 监控告警 | 日志分析、异常检测、资产清点 | API08、API09、API10 |
| 安全配置 | 最小权限、错误处理、HTTPS | API08、API10 |
十、总结
API安全测试应遵循一套系统化的方法论,确保覆盖全面。推荐的测试流程为:资产发现(梳理所有API端点,包括文档泄露、JS提取、目录爆破)→认证分析(测试认证机制强度,检查Token管理)→授权测试(BOLA水平/垂直越权、BFLA功能越权)→输入验证(注入、Mass Assignment)→业务逻辑(敏感流程滥用、业务漏洞)→速率限制(资源消耗、DoS)→监控告警(日志完整性、异常检测)。
推荐学习资源:OWASP API Security Top 10官方文档(权威的API安全风险清单与防护指南)、PortSwigger Web Security Academy的API Testing模块(实战练习)、CrAPI(Completely Ridiculous API,OWASP出品的漏洞API靶场,覆盖API Top 10)。
此外,建议关注以下实战靶场和工具:VAmPI(轻量级漏洞API靶场)、DVWA-node(Node版DVWA)、Damn Vulnerable GraphQL(GraphQL漏洞靶场)。在实际工作中,将API安全测试集成到CI/CD流水线中,使用自动化扫描工具(如Nuclei、OWASP ZAP)在每个版本发布前执行安全扫描,才能真正实现安全左移。
API安全不是一次性工作,而是一个持续的过程。随着API的不断迭代和新增,安全测试也需要持续进行。建立完整的API资产清单、实施分层防护、配置持续监控,才能在攻防对抗中保持主动。
