找回密码
立即注册
搜索
发回帖 发新帖

6451

积分

1

好友

809

主题
发表于 昨天 21:16 | 查看: 4| 回复: 0

导语:GraphQL 用一种由 Facebook 开源的 API 查询语言,把 REST 一整套路由压缩成一个端点——查询、写入、订阅全部塞进同一条 POST。这把双刃剑的另一面也足够锋利:内省一开,等于把数据模型直接递到攻击者手里;再加上参数未过滤、批处理滥用、CSRF 防护缺失,整条攻击链几小时就能跑完。

一、GraphQL 是什么:单端点的双刃剑

传统 REST API 里,每个资源对应一个 URL,查询、写入、删除各走各的路径。GraphQL 换个思路:把后端整个数据模型抽象成一张“图”,客户端只用同一个端点(通常是 /graphql),发一条结构化查询就能精确取回所需字段——不多取,也不少取。

前端省去了为每个新字段等后端排期出接口的麻烦,但代价同样摆在明面上:同一个端点扛下了所有读写逻辑。攻击者只要能摸到一个 URL,就等于摸到了整个系统的入口。

GraphQL 文档中定义了三类操作:

  • query:只读,行为上类似 GET。
  • mutation:写入并返回结果,覆盖了 POST/PUT/DELETE 的职能。
  • subscription:长连接推送,用于实时订阅。

攻击者往往偏爱 mutation——一旦认证被绕过,直接改数据比读数据更“值钱”。

数据模型通过 Schema Definition Language(SDL,模式定义语言)来定义,每个类型的字段、类型、是否可空都写在这一份声明里。SDL 看着像配置文件,实际上是后端逻辑的真值来源:前端、后端、文档、IDE 自动补全全都围着它转。

二、内省查询:把数据模型直接送人

内省(Introspection)是 GraphQL 内建的元数据查询能力。任何 GraphQL 端点都暴露了三个特殊字段:

  • __schema:返回整个 schema 的结构
  • __type:返回某个具体类型的字段定义
  • __typename:返回被查询对象的类型名(字符串)

这套机制最初是为客户端自动补全和文档生成服务的,但攻击者拿它来绘制整张后端地图。

2.1 探测端点是否存在

先用一条最小查询确认目标是不是 GraphQL:

{ __typename }

所有 GraphQL 端点都会返回 {"data": {"__typename": "Query"}}。如果对方回 404,说明不是 GraphQL;如果回的是别的 JSON 结构,协议也对不上。

常见端点路径有这么几条:/graphql、/api、/api/graphql、/graphql/api、/graphql/graphql。PortSwigger 文档建议五条挨个试一遍,再叠上 /v1 后缀。

内省如果开着,下面的查询能一口气把整个 schema 拖出来:

{
  __schema {
    queryType { fields { name description } }
    mutationType { fields { name description } }
    types { name description }
  }
}

返回结果中包含每个 query、mutation、subscription 的字段名和注释。实战中不少团队把字段描述写成“删除用户”“重置密码”这类直白文字,相当于把攻击指南直接挂在 API 上。Hasura 教程给过更精简的版本:只想找 mutation 就只查 mutationType。

HackerOne 报告 #291531 就是一条典型路径:访问 /graphql,运行内省,拿到包含 PII(个人可识别信息)字段的完整 schema。报告 #1132803 中,running.com/en-in/graphql 一次拉出了所有查询、类型、字段和可用操作。HackerOne 官方博客在 2024 年 7 月还专门写过一篇:第三方子域的 GraphQL 端点开了内省,主站促销横幅系统的能力列表被全部拖出——攻击者顺势拿到 mutation 入口,绕过身份验证。

三、八大攻击面与四步探测法

3.1 攻击面全景

GraphQL 攻击面全景图

day20 原文列出了八类 GraphQL 攻击,可以归到三个维度:

认证授权类

协议设计类

  • 内省查询开启(上面刚讲过)
  • Debug 模式开启(堆栈、源码、查询日志外泄)
  • 应用层 DoS(嵌套查询、字段别名、批处理把数据库打爆)

注入与泄漏类

  • SQL 注入(参数拼进 ORM)
  • 错误信息数据泄漏(报错里带回 PII)

3.2 探测四步法

PortSwigger 推荐的测试流程大致是这样:

  1. 找端点:五条常用路径加上 GET/POST/x-www-form-urlencoded 三种方法轮着试。
  2. 跑内省:就是上面那段 __schema 查询,跑一次。
  3. 看 Web 流量:如果目标网站本身在用 GraphQL,打开浏览器开发者工具或 Burp 看真实查询,照着它的结构改。
  4. 捅参数:用 IDOR 思路改 ID、改邮箱、改外键,看返回是否越权。

3.3 IDOR 实战例子

PortSwigger 文档里有个标准的教学场景:电商站用 GraphQL 列出已上架商品,返回 ID 为 1/2/4(缺了 3)。攻击者直接查:

query { product(id: 3) { id name listed } }

返回结果里 product 3 其实存在,只是没上架而已——这就是典型的“列表过滤了,但单查没过滤”。这类 BOLA(Broken Object Level Authorization,破坏对象级授权)漏洞因为有内省辅助,枚举所有带 id 参数的类型非常快。

四、批处理与限速绕过

GraphQL 支持一个请求里发多个查询(batch / alias),攻击者正好拿这个来绕过限速。直接用别名让同一个 mutation 跑一百次:

mutation {
  a: login(usr:"admin",pwd:"a") { token }
  b: login(usr:"admin",pwd:"b") { token }
  ...
}

WAF 只数 HTTP 请求数,不看里面的别名,一百次登录尝试就只是一个 POST。Directus 在 CVE-2024-39895 里栽过这个跟头,CVSS(通用漏洞评分系统)6.5,普通认证用户就能把数据库负载线性放大。

五、防御五要点

  1. 生产环境关掉内省:Apollo、Hasura、graphql-java 都支持 introspection: false,线上必须关。
  2. 强制 POST + application/json:拒绝 GET 和 x-www-form-urlencoded,从源头掐掉 CSRF(跨站请求伪造)。
  3. 字段级授权:用 graphql-shield 等库做 resolver(解析函数)级鉴权,别只看“有没有登录”。
  4. 深度/复杂度限制:限制嵌套层数和字段数,挡住单查询 DoS;别名查询要单独计数。
  5. 错误信息脱敏:生产环境不回 stack trace 和原始 SQL,统一改成“内部错误”。

六、思考题

  1. 如果目标站用的是 GraphQL,你会先用哪一条 query 确认它在线?
  2. 内省被关掉之后,还有什么办法能推断 schema 结构?
  3. mutation 列表里出现了 deleteUser,但没有任何角色校验——这属于哪一类攻击面?

素材出处

  1. learn365 day20 原文(GraphQL Series Part-1,About/Introspection/Attacks/Practice/References 五节框架)
  2. graphql.org Learn 教程(Schemas/Typed system/Introspection 章节)
  3. hasura.io GraphQL Introspection 教程(__schema / __type / __typename 三类查询示例)
  4. PortSwigger Web Security Academy GraphQL API Vulnerabilities(探测端点、IDOR、内省、批处理绕过)
  5. HackerOne 披露报告 #291531、#1132803
  6. HackerOne 博客 2024-07《How a GraphQL Bug Resulted in Authentication Bypass》
  7. Stingrai 2026 GraphQL API Vulnerabilities 综述
  8. dev.to 2026-09《GraphQL as Attack Surface: Introspection, Batching, and Schema Enumeration》



上一篇:Android恶意软件Midnight Mimosa曝光:预装固件层,波及150多国
下一篇:RollJam滚动码四步劫持实战:破解车钥匙Keeloq加密体系
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-10-13 00:55 , Processed in 0.069492 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表