云计算百科
云计算领域专业知识百科平台

GraphQL Yoga 安全加固实战:用 GraphQL Armor 为 GraphQL 服务器加装校验护栏

  • 后端
  • API设计

【免费下载链接】graphql-yoga

🧘 Rewrite of a fully-featured GraphQL Server with focus on easy setup, performance & great developer experience. The core of Yoga implements WHATWG Fetch API and can run/deploy on any JS environment.

项目地址:
https://gitcode.com/gh_mirrors/gr/graphql-yoga

点击查看 免费下载

本篇以 GraphQL Yoga 仓库中的 examples/graphql-armor 示例为主体,讲解如何把 GraphQL Armor 这一基于 Envelop 的安全中间件集成进 createYoga 创建的服务器,实现对恶意或异常 GraphQL 请求的拦截。读完本文,你将能够在本仓库示例基础上独立配置 Armor 插件、理解其插件注入 Envelop 编排器的底层链路,并通过 curl 与集成测试验证各项防护措施的生效效果。

示例定位与快速上手

examples/graphql-armor 是一个可独立运行的最小化示例,其 package.json 中的描述为 "Adding security layer to GraphQL Yoga using GraphQL Armor"。目录结构非常简洁:

  • examples/graphql-armor/src/yoga.ts:创建 Yoga 实例并挂载 Armor 插件;
  • examples/graphql-armor/src/main.ts:基于 node:http 启动 HTTP 服务;
  • examples/graphql-armor/integration-tests/graphql-armor.spec.ts:验证防护行为的集成测试。

在仓库根目录执行以下命令即可启动示例服务(该示例通过 pnpm workspace 的 –filter 定位到 example-graphql-armor 包):

pnpm –filter example-graphql-armor start

服务启动后监听 4000 端口,端点为 /graphql(见 examples/graphql-armor/src/main.ts 中的 server.listen(4000, …) 与 yoga.graphqlEndpoint 拼接日志)。其依赖锁定为 @escape.tech/graphql-armor@3.1.7、graphql@17.0.2 与 workspace 内的 graphql-yoga(见 examples/graphql-armor/package.json),因此本文描述的行为均以此为适用前提。

核心实现:把 Armor 插件交给 createYoga

示例的核心代码在 examples/graphql-armor/src/yoga.ts:

import { versionInfo } from 'graphql';
import { createSchema, createYoga, Plugin } from 'graphql-yoga';
import { EnvelopArmor } from '@escape.tech/graphql-armor';

const armor = new EnvelopArmor();
const enhancements = armor.protect();

export const yoga = createYoga({
plugins: [
…enhancements.plugins,
// In GraphQL>=17 we have the `hideSuggesstions` option instead.
…(versionInfo.major >= 17
? [
{
onValidate(params) {
params.setValidationFn((s, d, r, options) =>
params.validateFn(s, d, r, { …options, hideSuggestions: true }),
);
},
} satisfies Plugin,
]
: []),
],
schema: createSchema({
typeDefs: /* GraphQL */ `
type Book {
title: String
author: String
}
type Query {
books: [Book]
}
`,
resolvers: {
Query: {
books: () => booksStore,
},
},
}),
});

这段代码包含三层关键信息:

  • Armor 初始化与插件提取:new EnvelopArmor() 创建防护器实例,armor.protect() 返回的 enhancements.plugins 是一组 Envelop 插件,直接展开进 createYoga 的 plugins 数组即可生效——无需任何适配层,因为 Yoga 的插件体系本身就是 Envelop 插件体系。
  • GraphQL 17 的兼容性分支:从源码结构看,GraphQL 17 起 graphql-js 提供了原生的 hideSuggestions 校验选项。示例据此用 versionInfo.major >= 17 做了分支:在 17 及以上版本,通过一个额外的 onValidate 钩子插件,用 params.setValidationFn 包装原始 validateFn,把 hideSuggestions: true 合并进校验选项,让官方校验器自身不再输出字段建议;低于 17 的版本则依赖 Armor 自身的建议屏蔽能力。
  • schema 与 resolver:createSchema 定义了 Book 类型和 books 查询,数据来自内存中的 booksStore 数组(两本书),为后续验证 curl 请求提供了可预期的固定响应。
  • Armor 插件为何能直接注入 Yoga

    createYoga 的 plugins 参数接受的就是 Envelop 插件。从 packages/graphql-yoga 的入口 packages/graphql-yoga/src/index.ts 可以看到,Yoga 直接透传了 @envelop/core 的 envelop、useEnvelop、useExtendContext 等核心能力,并导出了 Plugin 类型(packages/graphql-yoga/src/plugins/types.js)。因此 enhancements.plugins 与普通 Yoga 内置插件处于同一执行链上:每个插件的 onValidate、onExecute 等钩子都会被 Envelop 编排器统一调度。

    校验函数的替换机制可在 Envelop 核心源码中印证。packages/envelop/core/src/orchestrator.ts 中,编排器维护一个可变的 validateFn(初始为 graphql 包导出的 validate),并通过 onValidate 钩子参数暴露 setValidationFn 供插件替换,最终执行校验时调用的是被替换后的 validateFn。示例中 GraphQL 17 分支里 params.setValidationFn(…) 正是利用这一机制,在不修改 Armor 输出的前提下追加 hideSuggestions 选项。

    支持的安全措施

    README 声明该示例(配合 Armor 默认配置)覆盖以下整改措施(remediations):

    • Aliases Limit:限制别名数量,防止通过海量别名放大执行成本;
    • Character Limit:限制查询文档总字符数,拦截超长查询;
    • Cost Limit:按查询复杂度成本进行限制;
    • Depth Limit:限制查询字段嵌套深度,防止深层嵌套拖垮执行;
    • Directives Limit:限制指令(directive)使用数量;
    • Disabled Field Suggestion:在"字段不存在"的校验错误中屏蔽字段建议,避免借助拼错字段名的报错逐字探测 schema。

    这些措施对应 Armor 自身的配置项,示例中 new EnvelopArmor() 使用的是其内置默认阈值;如需调整(如放宽 maxDepth、关闭某项防护),可在 EnvelopArmor 构造函数的配置对象中修改,本仓库示例未展开这部分,需参照 Armor 项目自身的文档。

    防护效果验证

    合法查询应正常通过

    对端点发起合法查询,应返回数据而非被 Armor 拦截:

    $ curl –location –request POST 'http://localhost:4000/graphql' \\
    –header 'Content-Type: application/json' \\
    –data-raw '{"query":"query { books { title } }"}'

    {"data":{"books":[{"title":"The Awakening"},{"title":"City of Glass"}]}}

    字段建议被屏蔽

    故意查询一个不存在的字段 titlee(README 原文写作 title[e],示例 payload 实为 titlee):

    $ curl –location –request POST 'http://localhost:4000/graphql' \\
    –header 'Content-Type: application/json' \\
    –data-raw '{"query":"query { books { titlee } }"}'

    {"data":null,"errors":[{"message":"Cannot query field \\"titlee\\" on type \\"Book\\". [Suggestion message hidden by GraphQLArmor]?","locations":[{"line":1,"column":17}],"extensions":{}}]}

    错误消息中原本 graphql-js 会附带的 "Did you mean title?" 建议被屏蔽——这正是 Disabled Field Suggestion 的价值:攻击者无法通过拼错字段名再读取建议来无成本地枚举 schema。

    集成测试对行为的固化

    examples/graphql-armor/integration-tests/graphql-armor.spec.ts 通过 yoga.fetch(…) 直接对内存中的 Yoga 实例发起请求,覆盖两个断言:

  • query{books{title}} 应无 errors 且 data 与内联快照一致;
  • query{books{titlee}} 应恰好产生 1 条 errors,extensions.code 为 GRAPHQL_VALIDATION_FAILED,且 data 为假值。测试同样做了版本分支:graphql 主版本 >= 17 时期望消息为干净的 Cannot query field "titlee" on type "Book".(来自原生 hideSuggestions),否则期望 Cannot query field "titlee" on type "Book". [Suggestion hidden](来自 Armor 的提示替换)。
  • 这段测试也解释了 README 中 curl 输出与测试快照在措辞上的细微差异:两者分别对应 Armor 的提示替换与 GraphQL 17 原生隐藏建议两种实现路径。

    小结与使用要点

    • 集成成本极低:new EnvelopArmor() + armor.protect().plugins 展开进 createYoga 的 plugins 即完成接入,示例完整实现不足 60 行(examples/graphql-armor/src/yoga.ts);
    • 插件生效依赖 Yoga 对 Envelop 钩子的原生调度,setValidationFn 机制的底层实现见 packages/envelop/core/src/orchestrator.ts;
    • 当前仓库锁定的依赖版本为 @escape.tech/graphql-armor@3.1.7、graphql@17.0.2;若你使用 graphql 16,行为会走 Armor 自身的建议屏蔽路径,若使用 17 及以上,则如示例所示叠加原生 hideSuggestions;
    • 示例默认阈值适用于演示,生产环境建议结合自身查询复杂度与业务特征显式配置各项 limit,并通过类似本示例的集成测试固化防护行为,防止回归。

    赞

    分享

    • 后端
    • API设计

    【免费下载链接】graphql-yoga

    🧘 Rewrite of a fully-featured GraphQL Server with focus on easy setup, performance & great developer experience. The core of Yoga implements WHATWG Fetch API and can run/deploy on any JS environment.

    项目地址:
    https://gitcode.com/gh_mirrors/gr/graphql-yoga

    点击查看 免费下载

    上一篇:
    Chroma常见问题解答:解决开发中遇到的典型问题

    下一篇:
    GitHub Training Kit项目管理:GitHub Professional Services团队的工作方法

    创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » GraphQL Yoga 安全加固实战:用 GraphQL Armor 为 GraphQL 服务器加装校验护栏
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!