尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

GraphiQL Introspection Schema XSS(CVE-2021 模板注入):漏洞分析、防御纵深与修复实践指南

发布时间:2026/9/14 0:14:41

资讯中心
01
ARTICLE

GraphiQL Introspection Schema XSS(CVE-2021 模板注入):漏洞分析、防御纵深与修复实践指南

GraphiQL Introspection Schema XSS(CVE-2021 模板注入):漏洞分析、防御纵深与修复实践指南
GraphiQL Introspection Schema XSSCVE-2021 模板注入漏洞分析、防御纵深与修复实践指南【免费下载链接】graphiqlGraphiQL the GraphQL LSP Reference Ecosystem for building browser IDE tools.项目地址: https://gitcode.com/GitHub_Trending/gr/graphiqlGraphiQL 是 GraphQL 生态中最常用的交互式 IDE 工具其核心工作方式是通过 introspection内省请求获取服务器 schema 并在前端渲染。本文基于仓库 docs/security/2021-introspection-schema-xss.md 这一安全公告完整剖析一类针对 GraphiQL 的 XSS 攻击攻击者通过恶意 schema 中的类型名type name在操作自动补全autocomplete环节注入可执行代码。你将掌握该漏洞的成因、影响范围、graphiql1.4.7的三层防御修复方案、旧版本加固的 workaround以及如何结合当前仓库源码与测试用例亲手复现并验证修复效果。1. 漏洞概述从 introspection schema 到动态 XSS这是一份针对graphiql包的安全公告描述的是一类introspection schema 模板注入template injection攻击graphiql1.4.7之前的所有版本都会在收到被攻陷的 HTTP introspection schema 响应或收到带有恶意 GraphQL 类型名的schemaprop 值时暴露一个动态 XSS 攻击面使得攻击者可以在**操作自动补全operation autocomplete**时注入并执行任意代码。这里“模板注入”指GraphiQL 曾把来自 GraphQL 服务器的类型名等字符串直接插值进 HTML而非作为文本转义类型名本身在 GraphQL 语言中扮演着“模板占位符”的角色——一旦攻击者能够控制 schema 内容也就控制了渲染模板中的注入点。当自动补全列表渲染包含img srcx onerror...这类载荷的类型名时浏览器就会把它当作真实 HTML 解析并执行。该漏洞同样影响graphiql的分支项目graphql-playground以及由 Apollo Server 分发的graphql-playground版本。由于这条 XSS 攻击面存在威胁行为者可以在用户毫无察觉的情况下利用任意恶意脚本窃取用户凭据、数据等敏感信息。1.1 攻击成立的两个必要条件要成功发起攻击需要同时满足两个条件参见公告第 2 节条件一GraphiQL web 应用信任其对应 GraphQL 服务器提供的信息将类型名等信息直接插值进 HTML而不是做适当的转义或净化。这正是 1.4.7 之前所有版本存在的问题——它们过度信任服务器提供的类型名同时依赖markdown-it包的 XSS 过滤来保护 description 和 deprecationReason 字段。条件二受害者能够以“让 GraphiQL 与攻击者控制的 GraphQL 服务器通信”的方式加载该 web 应用。第二个条件是关键默认情况下graphiql并不允许攻击者控制它连接哪个 GraphQL 服务器因此大量默认安装并不受此公告影响。只有满足以下情况才会受影响传入的fetcher参数允许任意定制 GraphQL 端点例如从 URL 参数读取 GraphQL 地址或攻击者通过其他途径影响 GraphQL 服务器返回的 introspection schema。公告还给出了“其他途径”的一个典型例子如果你把 GraphiQL 作为某个PaaS 平台的一部分对外提供服务允许用户定义自己的 GraphQL schema——此时即使 GraphiQL 硬编码连接单个端点攻击者仍能控制该端点并借此向 GraphiQL 注入脚本。这类场景下只要 GraphiQL 在未先验证 schema 的情况下响应 introspection 请求就存在漏洞。反过来GraphQL 服务器可以**拒绝在无效 schema 上执行操作包括 introspection 操作**来防范此类攻击——任何用graphql-js构建的服务器在执行前都会正确校验 schema。1.2 影响范围受影响所有已发布的graphiql版本即 1.4.7 之前的全部版本以及所有graphiql的分支如graphql-playground及其 Apollo Server 发行版——后两者由于默认解析 URL 参数受影响程度更严重详见 graphql-playground 公告 与 Apollo Server 公告。不受影响该漏洞位于graphiql的onHasCompletion.ts中因此codemirror-graphql、monaco-graphql及其他下游依赖不受影响。桌面客户端Altair、Insomnia、Postwoman 等桌面客户端目前看来不受此漏洞影响。1.3 致谢该漏洞由 Ry0taK 发现imolorhe、glasser、divyenduz、dotansimha、acao、benjie 等多人参与修复。2. 修复方案graphiql1.4.7的纵深防御Defense in Depthgraphiql1.4.7通过三层纵深防御修复该问题任何一层单独都能堵住已知漏洞2.1 第一层对应当按文本处理的 HTML 进行转义对“应作为文本而非 HTML 处理”的内容做HTML 转义HTML-escaping。在应用的大部分区域React 默认会对所有插值文本做转义因此这项工作自动完成但唯一一个脆弱的组件使用了不安全的innerHTMLAPI将类型名直接插值进 HTML。1.4.7 现在会正确转义该类型名从而修复已知漏洞。2.2 第二层收到 introspection 响应或 schema 变化时校验 schema在收到 introspection 响应或 schema 发生变化时校验 schema凡是名称违反 GraphQL 规范Names must match/^[_a-zA-Z][_a-zA-Z0-9]*$/的 schema 将不再被加载同时也会阻止 Doc Explorer 加载。这一变更本身也足以修复已知漏洞。该层校验可通过dangerouslyAssumeSchemaIsValid{true}关闭——一旦关闭意味着你只能依赖第一层的转义来抵御攻击。从当前仓库源码可以确认该 prop 的完整语义与默认值默认值为false见 packages/graphiql-react/src/components/provider.tsxprovider 在 schema prop 变化时执行校验逻辑只有dangerouslyAssumeSchemaIsValid为true时才跳过validateSchema(newSchema)见 provider.tsx类型定义与警告注释明确说明不校验 schema 时GraphiQL 及其组件容易受到多种漏洞利用并可能崩溃只有完全掌控传入 schema 时才应使用该 prop见 packages/graphiql-react/src/stores/schema.ts。对应地仓库中的 E2E 测试packages/graphiql/cypress/e2e/errors.cy.ts正是用恶意 schema fixture 验证了这条链路拦截/graphql请求返回bad-schema.json后GraphiQL 会展示形如Names must only contain [_a-zA-Z0-9] but img srcx onerroralert(document.的验证错误——恶意 schema 被成功拦截。2.3 第三层确保用户生成的 HTML 是安全的markdown-it 加固schema 的description与deprecationReason字段可以包含 Markdownweb 应用会通过markdown-it库将其渲染为 HTML。1.4.7 开发过程中验证了 markdown-it 的使用方式能够阻止任意 HTML 混入使用markdown-it时未开启html: true因此可放心依赖 markdown-it 的 HTML 转义能力。团队也曾考虑再用dompurify之类的库对渲染结果做第二层净化但评估后认为markdown-it的净化已足够无需额外一层。此外1.4.7 把markdown-it从 v10 升级到了 v12以吸收 v11、v12 中的安全修复。从当前仓库实现看这条防线至今延续并升级markdown-it已更新至^14.2.0见 packages/graphiql-react/package.json单例实例配置为breaks: false, linkify: true同样未开启html: true见 packages/graphiql-react/src/utility/markdown.ts渲染时通过dangerouslySetInnerHTML注入markdown.render(children)的输出见 packages/graphiql-react/src/components/markdown-content/index.tsx因此这条 HTML 入口的安全性完全取决于 markdown-it 的净化能力。2.4 CDN 实现可能已被自动修复如果你的实现依赖 CDN 版本且指向latest标签多数 CDN 未指定版本时的默认行为则该问题已被自动缓解——即使此前存在漏洞。3. 旧版本加固Workarounds如果无法升级到graphiql1.4.7或更高版本始终使用指向可信服务器的静态 URL确保该服务器提供可信的 GraphQL schema如果你的自定义实现允许通过 URL 查询参数、数据库值等使用用户提供的 schema URL必须禁用该定制能力或只允许受信任的 URL。4. 如何复现攻击Exploit Re-creation公告提供了完整的复现路径可用任意 1.4.6 及更早版本1.4.6 是最后一个受影响版本验证准备一个自定义fetcher使其接受 URL 参数来指定 GraphQL 端点这正是 phishing 攻击面的演示方式。注意类似url参数并非攻击发生的必要条件——只要fetcher以其他方式与受攻陷的 GraphQL 服务器通信攻击同样成立。在浏览器地址中附加?urlhttps://graphql-xss-schema.netlify.app/graphql该端点托管着恶意 schema。清空编辑器中的查询内容输入{u——自动补全触发渲染恶意类型名弹出 alert 窗口证明攻击者控制的代码被执行。关于验证异常公告有两个重要的工程细节React 开发模式下验证异常会可见地抛出但在production 构建中该异常通常被埋没在浏览器控制台不阻断攻击。这个验证异常来自getDiagnostics它会调用graphql的validate()后者进而调用assertValidSchema()——与apollo-server-core每次执行操作时所做的校验一致。该验证本身并不能阻止攻击成功修复前的版本存在但不构成防护。4.1 复现所用恶意 schema 的仓库证据公告第 3 节给出了完整载荷示例原始出处为 packages/graphiql/test/bad-schema.js在当前仓库中的路径为 packages/graphiql/test/bad-schema.js。恶意点在于introspection schema 中的任意NamedType字段名、输入对象名、枚举名、变量名等凡其名称会渲染进自动补全列表的都可以携带被攻陷的name值{ kind: OBJECT, name: img srcx onerroralert(document.domain), description: null, fields: [ { name: name, description: null, args: [], type: { kind: NON_NULL, name: null, ofType: { kind: SCALAR, name: String, ofType: null } }, isDeprecated: false, deprecationReason: null } ], inputFields: null, interfaces: [], enumValues: null, possibleTypes: null }当前仓库的 packages/graphiql/cypress/fixtures/bad-schema.json 是同一恶意载荷的 introspection 响应形态Query.user字段的返回类型被命名为img srcx onerroralert(document.domain)且 schema 中还存在一个同名 OBJECT 类型。这正是 E2E 测试packages/graphiql/cypress/e2e/errors.cy.ts用来验证“schema 无效时报错”的输入。5. 修复后的源码级验证链路结合当前仓库已是修复后状态可以完整还原“修复前/修复后”的对照逻辑schema 来源schemaprop 可以为GraphQLSchema、IntrospectionQuery或null。undefined时 GraphiQL 会通过fetcher发起 introspection 请求见 packages/graphiql-react/src/stores/schema.tsintrospection 响应会经buildClientSchema(introspectionData)构建为GraphQLSchema见 schema.ts。验证时机无论 schema 来自 introspection 还是schemaprop在 provider 的useEffect中都会执行validateSchema(newSchema)除非显式设置dangerouslyAssumeSchemaIsValid见 provider.tsx。验证结果validateSchema来自graphql包见 provider.tsx非法名称会在这一步被拒绝恶意 schema 无法进入自动补全渲染流程。Markdown 渲染防线markdown-it单例未开启html: true见 markdown.tsdescription 与 deprecationReason 中的原始 HTML 会被转义为文本。6. 总结与安全建议针对本次 introspection schema 模板注入 XSS 攻击本仓库给出的完整安全实践可以归纳为升级尽快升级到graphiql1.4.7或更高版本当前仓库各包的 CHANGELOG 记录了后续对markdown-it的持续升级例如 v14.x见 packages/graphiql/CHANGELOG.md。默认配置即安全保持默认行为——schema URL 不可被攻击者控制、dangerouslyAssumeSchemaIsValid保持默认falseGraphiQL 会自动拦截非法 schema。自定义 fetcher 需谨慎任何允许用户指定端点的实现URL 参数、数据库取值等都会放大攻击面应按公告 workaround 禁用或限定为可信 URL。服务器侧联动防御GraphQL 服务器应在执行任何操作含 introspection前校验自身 schemagraphql-js构建的服务器天然具备此行为。保留校验红线dangerouslyAssumeSchemaIsValid{true}只能在你完全掌控传入 schema 时使用否则等同于放弃第二层防御。【免费下载链接】graphiqlGraphiQL the GraphQL LSP Reference Ecosystem for building browser IDE tools.项目地址: https://gitcode.com/GitHub_Trending/gr/graphiql创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。