跳到主要内容

GraphQL 发现与 Introspection 信息泄露

GraphQL 把“接口”折叠成一个端点:所有查询都发往同一 URL,__schema 这类内置字段又能让客户端 枚举整个 schema。测试的第一步是找到端点,第二步是确认 introspection 是否开放。


端点指纹

GraphQL 端点对非 POST 请求有特征回应。最常见的探测是直接 GET:

curl -sS http://target/graphql
# GET query missing.

返回 GET query missing. 之类的提示,基本可以确认这是 GraphQL 端点。

其他辅助特征:

特征说明
GET 返回 query missing 提示端点存在但请求方式不对
CORS 全开 + Express 弱 ETagApollo Server(基于 Express)的框架特征组合
错误堆栈泄露绝对路径服务端调试信息未关闭,泄露部署结构
# 观察响应头特征
curl -sSI -H 'Origin: http://evil.example' http://target/graphql

常见位置

端点不一定在根路径,先枚举常见路径再确认指纹:

/graphql
/graphiql
/api/graphql
/v1/graphql

路径发现流程可参考 ffuf 快速模糊枚举


Introspection 还原 schema

GraphQL 内置自省(introspection)能力,标准查询可以直接枚举类型与字段:

query {
__schema {
types {
name
fields {
name
}
}
}
}

从返回结果能还原出完整的 schema:有哪些查询入口、哪些对象类型、每个类型暴露哪些字段。schema 是后续所有测试的地图——没有权限控制时,schema 里写出来的字段往往就是可查的

直接查询敏感字段

还原 schema 后,观察是否存在把敏感数据直接暴露为普通字段的类型(典型如用户类型同时带 usernamepassword):

query {
users {
username
password
}
}

若查询成功返回明文口令哈希甚至明文,即为一次完整拖库。这通常出现在 字段级鉴权缺失 的实现里:接口只做了“能不能进 GraphQL”的判断,没做“哪些字段能不能读”的判断。


Apollo Server 常见暴露

Apollo Server 是最常见的 GraphQL 实现,测试中反复出现同一组暴露面:

暴露面风险
生产环境未关 introspection完整 schema 泄露
CORS 全开任意来源可携带跨域请求读取数据
详细错误堆栈泄露绝对路径与内部结构
默认无字段级鉴权敏感字段随 schema 一起可查

复核要点

检查点说明
端点确认GET 特征提示 + 常见路径枚举双确认
introspection 状态__schema 查询是否返回完整类型
敏感字段逐个检查用户、凭据、内部状态类类型
错误信息故意构造非法查询观察堆栈详细程度
认证边界无 token 与带 token 的查询结果差分

防御建议

  1. 生产环境禁用 introspection,schema 只在开发/文档环境提供。
  2. 实施字段级鉴权:敏感字段(口令、内部 ID)在 resolver 层显式校验,而不是只在端点入口判断。
  3. 限制查询深度与复杂度,防止嵌套查询打瘫后端。
  4. 收紧 CORS,不使用全开源放。
  5. 关闭详细错误堆栈,生产环境只返回通用错误信息。