如何防止对 GraphQL/Apollo 服务器的嵌套攻击?
How do you prevent nested attack on GraphQL/Apollo server?
如何使用如下查询防止对 Apollo 服务器的嵌套攻击:
{
authors {
firstName
posts {
title
author {
firstName
posts{
title
author {
firstName
posts {
title
[n author]
[n post]
}
}
}
}
}
}
}
换句话说,如何限制查询中提交的递归数?这可能是一个潜在的服务器漏洞。
截至撰写本文时,GraphQL-JS 或 Apollo Server 中还没有内置功能来处理这个问题,但随着 GraphQL 变得越来越流行,这绝对应该有一个简单的解决方案。这个问题可以通过堆栈的多个级别的几种方法来解决,并且还应该始终与速率限制相结合,这样人们就不能向您的服务器发送太多查询(这也是 REST 的一个潜在问题)。
我只会列出我能想到的所有不同方法,并且我会尽量使这个答案保持最新,因为这些解决方案已在各种 GraphQL 服务器中实现。有些很简单,有些比较复杂。
- 查询验证:在每个 GraphQL 服务器中,运行 查询的第一步是 验证 - 这就是服务器会尝试确定查询中是否存在任何严重错误,这样我们就可以在发现语法错误或无效参数之前避免使用实际的服务器资源。 GraphQL-JS 自带 a selection of default rules that follow a format pretty similar to ESLint. Just like there is a rule to detect infinite cycles in fragments,可以编写一个验证规则来检测嵌套过多的查询,并在验证阶段拒绝它们。
- 查询超时:如果无法静态地检测到查询过于耗费资源(也许即使是浅查询也可能非常昂贵!),那么我们可以简单地为查询执行添加超时。这有几个好处:(1) 这是一个不难推理的硬性限制,(2) 这也有助于解决其中一个后端响应时间过长的情况。在许多情况下,您的应用程序的用户宁愿缺少字段也不愿等待 10 秒以上才能获得响应。
- 查询白名单:这可能是最复杂的方法,但您可以提前编制一个允许查询的列表,并根据该列表检查任何传入的查询。如果您的查询是完全静态的(您没有在客户端使用 Relay 之类的东西生成任何动态查询),这是最可靠的方法。您可以使用自动化工具在部署时从您的应用程序中提取查询字符串,这样在开发中您可以编写您想要的任何查询,但在生产中只允许您想要的查询。这种方法的另一个好处是您可以完全跳过查询验证,因为您知道所有可能的查询都已经有效。有关静态查询和白名单的更多好处,请阅读此 post:https://dev-blog.apollodata.com/5-benefits-of-static-graphql-queries-b7fa90b0b69a
- 查询成本限制:(在编辑中添加)类似于查询超时,您可以在查询执行期间为不同的操作分配成本,例如数据库查询,并限制客户端每次查询能够使用的总成本。这可以与限制单个查询的最大并行度相结合,这样您就可以防止客户端向您的后端发送发起数千个并行请求的内容。
(1) 和 (2) 可能是每个 GraphQL 服务器默认应该有的东西,特别是因为许多新开发人员可能没有意识到这些问题。 (3) 仅适用于某些类型的应用程序,但在对性能或安全性要求非常严格时可能是一个不错的选择。
为了补充 Stubailo 的回答中的第 (4) 点,这里有一些 Node.js 实现对传入的 GraphQL 文档施加 成本和深度范围 。
这些是补充验证阶段的自定义规则。
查询白名单的一个变体是查询签名。
在构建过程中,每个查询都使用与服务器共享但不与客户端捆绑的秘密进行加密签名。然后在运行时服务器可以验证查询是否真实。
与白名单相比的优势在于,在客户端中编写查询不需要对服务器进行任何更改。如果多个客户端访问同一服务器(例如 Web、桌面和移动应用程序),这尤其有价值。
对于查询成本限制,您可以使用 graphql-cost-analysis
这是一个验证规则,它在执行查询之前解析查询。在您的 GraphQL 服务器中,您只需为您想要的架构类型映射的每个字段分配成本配置。
不要错过 graphql-rate-limit GraphQL 指令,为您的查询或变更添加基本但精细的速率限制。
如何使用如下查询防止对 Apollo 服务器的嵌套攻击:
{
authors {
firstName
posts {
title
author {
firstName
posts{
title
author {
firstName
posts {
title
[n author]
[n post]
}
}
}
}
}
}
}
换句话说,如何限制查询中提交的递归数?这可能是一个潜在的服务器漏洞。
截至撰写本文时,GraphQL-JS 或 Apollo Server 中还没有内置功能来处理这个问题,但随着 GraphQL 变得越来越流行,这绝对应该有一个简单的解决方案。这个问题可以通过堆栈的多个级别的几种方法来解决,并且还应该始终与速率限制相结合,这样人们就不能向您的服务器发送太多查询(这也是 REST 的一个潜在问题)。
我只会列出我能想到的所有不同方法,并且我会尽量使这个答案保持最新,因为这些解决方案已在各种 GraphQL 服务器中实现。有些很简单,有些比较复杂。
- 查询验证:在每个 GraphQL 服务器中,运行 查询的第一步是 验证 - 这就是服务器会尝试确定查询中是否存在任何严重错误,这样我们就可以在发现语法错误或无效参数之前避免使用实际的服务器资源。 GraphQL-JS 自带 a selection of default rules that follow a format pretty similar to ESLint. Just like there is a rule to detect infinite cycles in fragments,可以编写一个验证规则来检测嵌套过多的查询,并在验证阶段拒绝它们。
- 查询超时:如果无法静态地检测到查询过于耗费资源(也许即使是浅查询也可能非常昂贵!),那么我们可以简单地为查询执行添加超时。这有几个好处:(1) 这是一个不难推理的硬性限制,(2) 这也有助于解决其中一个后端响应时间过长的情况。在许多情况下,您的应用程序的用户宁愿缺少字段也不愿等待 10 秒以上才能获得响应。
- 查询白名单:这可能是最复杂的方法,但您可以提前编制一个允许查询的列表,并根据该列表检查任何传入的查询。如果您的查询是完全静态的(您没有在客户端使用 Relay 之类的东西生成任何动态查询),这是最可靠的方法。您可以使用自动化工具在部署时从您的应用程序中提取查询字符串,这样在开发中您可以编写您想要的任何查询,但在生产中只允许您想要的查询。这种方法的另一个好处是您可以完全跳过查询验证,因为您知道所有可能的查询都已经有效。有关静态查询和白名单的更多好处,请阅读此 post:https://dev-blog.apollodata.com/5-benefits-of-static-graphql-queries-b7fa90b0b69a
- 查询成本限制:(在编辑中添加)类似于查询超时,您可以在查询执行期间为不同的操作分配成本,例如数据库查询,并限制客户端每次查询能够使用的总成本。这可以与限制单个查询的最大并行度相结合,这样您就可以防止客户端向您的后端发送发起数千个并行请求的内容。
(1) 和 (2) 可能是每个 GraphQL 服务器默认应该有的东西,特别是因为许多新开发人员可能没有意识到这些问题。 (3) 仅适用于某些类型的应用程序,但在对性能或安全性要求非常严格时可能是一个不错的选择。
为了补充 Stubailo 的回答中的第 (4) 点,这里有一些 Node.js 实现对传入的 GraphQL 文档施加 成本和深度范围 。
这些是补充验证阶段的自定义规则。
查询白名单的一个变体是查询签名。
在构建过程中,每个查询都使用与服务器共享但不与客户端捆绑的秘密进行加密签名。然后在运行时服务器可以验证查询是否真实。
与白名单相比的优势在于,在客户端中编写查询不需要对服务器进行任何更改。如果多个客户端访问同一服务器(例如 Web、桌面和移动应用程序),这尤其有价值。
对于查询成本限制,您可以使用 graphql-cost-analysis
这是一个验证规则,它在执行查询之前解析查询。在您的 GraphQL 服务器中,您只需为您想要的架构类型映射的每个字段分配成本配置。
不要错过 graphql-rate-limit GraphQL 指令,为您的查询或变更添加基本但精细的速率限制。