于10月8日至10日加入我们,在纽约市学习有关 GraphQL 联邦和 API 平台工程的最新技巧、趋势和新闻。参加2024年纽约市的 GraphQL峰会
文档
免费开始

保护超级图

保护联邦GraphQL API的最佳实践

安全联邦

从您用来减少任何API攻击面的相同标准方法中受益。以下提供了关于一些最常见风险的辅助总结。OWASP Top Ten 列表提供了一些最常见风险的有益总结。

此外,还有一些与GraphQL相关的特定动作,您必须采取这些动作以限制您的 面对潜在威胁的易受攻击性。这些威胁大多与拒绝服务(DoS)攻击有关,它们属于API可发现性和恶意查询的类别。

API可发现性

限制GraphQL API在生产环境中的可发现性是防范潜在攻击者的重要措施之一。尽管GraphQL API的内建可发现性在本地开发时可以增强开发者的使用体验,但我们通常不希望非公开API在生产环境中提供相同的特性。以下部分将探讨一些限制API可发现性的关键方法。

在生产环境中关闭 introspection 功能

GraphQL 内置的 introspection 查询是恶意行为者了解您架构最快的方式。为了防止这种情况,请在生产环境的 supergraph 中关闭 introspection,并限制对任何启用 introspection 的预发布环境的访问。

注意

当使用 GraphOS Router 时,introspection 功能默认是关闭的。

关于GraphQL API滥用的这个视频深入探讨了introspection如何促进API滥用,以及关闭introspection并限制可发现性的额外措施为何同样重要。

在生产环境中隐藏错误详情

许多 通过在操作响应中提供详细的错误信息来改善开发者的使用体验。在您的生产 supergraph 中,请确保不要将详细的错误信息从API响应中移除。

例如,基于 Apollo-Server 的 默认提供以下 exception.stacktrace 属性,位于响应中的 errors 标签下。这个值在开发和调试服务器时非常有用,但不应该向面向公众的客户端暴露堆栈跟踪细节。

注意

GraphOS Router 默认省略所有错误数据。

您可能希望在生产环境中选择性地向客户端公开错误详情。您可以使用 GraphOS Router 的 'include_subgraph_errors' 选项和 Rhai 脚本 来操作响应。

避免自动生成架构

当降低您的 GraphQL API 的易发现性时,可以考虑的一种策略是尽可能避免自动生成模式,尤其是根操作类型上的目前有很多开发者工具允许您根据一组在模式定义或某些现有数据库表中的初始定义自动生成一个。尽管这些自动生成年方案的方案可以加快初始 API 开发速度,但它们也使恶意行为者更容易猜测基于常用模式自动生成的与 CRUD 相关的通用字段。

自动生成的模式还增加了您无意中通过您的GraphQL API 暴露敏感数据的风险。作为模式设计的最佳实践,您应该明确设计您的模式以满足客户端用例和产品需求。这有助于您的整个组织最大限度地利用您的supergraph

仅允许路由器直接查询子图

作为每个supergraph的最佳实践,只有应该直接查询个体Apollo Federation 子图规范指出,每个包括_entities_service字段,以协助如果客户端直接访问这些字段,这些字段会暴露子图额外的安全担忧。

Query._service对象包含一个,它包括子图模式的全表示。这个字段像标准内省查询一样披露有关子图模式的数据,这意味着它不应该在生产环境中可访问。

The Query._entities 场地启用路由器通过提供该实体 ID 解决标记有 @key 的任何类型的字段。如果这个场地公开暴露,这意味着任何客户端都可以绕过内部 逻辑,并模拟路由器来检索任何 数据。由于 _entities 的解析器是由您的子图库自动提供的,因此您也无法修改该逻辑。这意味着您将不得不手动检查所有包含 _entities 场地 的操作,并阻止任何恶意查询。

限制对子图访问的另一个原因与字段级跟踪有关。这种跟踪数据包含在从子图到路由器的响应的 extensions 键中,该数据根据查询计划聚合到跟踪形状中,然后发送到 。这意味着任何可以直接查询您的子图的客户端都可以在操作响应中查看这些数据,并根据它对子图进行推断。

除了上述安全担忧之外,防止外界直接访问子图也有助于确保客户端(甚至是善意客户端)仅将操作路由到汇总图,而不发明针对子图脚本研究中类型和字段的意外用法,这些类型和字段仅适用于执行路由器的查询计划。

恶意查询

在实现限制公共场合API可发现性的措施之后,保护GraphQL API的下一步是防御有意的和意外的恶意查询。同样,许多GraphQL相关的漏洞都与未受保护的API可能在DoS攻击中被利用的方式有关,但还有其他考虑事项。

在随后的部分中,我们将探讨可以帮助减轻任何GraphQL API恶意查询影响的措施,例如限制查询深度和数量、在适当的情况下分页列表字段、验证和清理数据、设置超时、在路由器中进行身份验证和授权,并防止批量查询滥用。对于具有第三方客户端的GraphQL API,我们还将探讨使用查询成本分析来支持速率限制。

限制查询深度

GraphQL允许客户端遍历图,并在操作的选择集中表达节点之间的复杂关系。但在没有限制查询嵌套深度的保护措施的情况下,这可能会变得过多。例如:

query DeepBlogQuery {
author(id: 42) {
posts {
author {
posts {
author {
posts {
author {
# and so on...
}
}
}
}
}
}
}
}

此类深层次查询最直接的防护措施之一是设置最大 查询 深度。因为 操作 可以指定多个根 字段,您还可以考虑在根级别限制查询宽度。

在合适的位置分页字段

分页 字段 是另一个控制客户端一次请求多少项的重要机制。例如,一个 Posts 子图 服务可能没有问题解决这个请求中的总共 Post 个对象:

query {
authors(first: 10) {
name
posts(last: 100) {
title
content
}
}
}

当每个 字段 的数量级增加,且请求了十万以上的 Post 时会发生什么?

query {
authors(first: 100) {
name
posts(last: 1000) {
title
content
}
}
}

分页 字段 时,设置单次响应可以返回的最大项目数非常重要。在上面的示例中,当尝试为每位作者返回一千条帖子时,你可能想执行 posts 字段 解析器时的 GraphQL 错误。

验证并清理数据

验证和清理客户端提交的数据对于任何 API 都很重要,supergraph 也不例外。通常,验证和清理不可信输入的规则也适用于 GraphQL,当根据用户提供的输入解决字段时。并且如前所述,当用户作为操作 提供无效值时,生产环境中导致错误的细节应尽可能少。

设计良好的 GraphQL 模式 也可以通过在类型中直接编纂验证和清理来保护免受注入攻击。例如,枚举值可以限制可以提交为 参数值 的值的范围,并且自定义 也能帮助验证、转义或规范化值。然而,应该谨慎处理自定义标量,因为误用它们可能会创建其他漏洞,例如 一个使 NoSQL 注入攻击成为可能的 JSON 标量类型

设置超时

超时是阻止 GraphQL 实际消耗比预期更多服务器资源的操作的有用工具。在一个 supergraph 中,超时通常应用于三个不同级别中的任何组合:

  • 在最高级别,您可以为 router's HTTP 服务器(或其前面的负载均衡器的空闲超时)设置超时。
  • 在中间级别,您可以为 router's 对单个 subgraphs 的请求设置超时。您可以使用 GraphOS Router 的流量整形配置 在 HTTP 和 subgraph 级别配置超时。
  • 在最细粒度级别,subgraphs可以为单个 operations 设置超时。在调用每个 field 解析器函数时,可以检查请求持续时间与该超时之间的关系。您可能需要使用解析器中间件或一个 插件在 subgraph 中实现这一点。

根据需要使用速率限制

特别是对于由第三方客户端使用的 GraphQL API,深度和广度限制以及分页的 fields 可能不足以提供足够的请求控制。对于这些情况,执行 API 请求的速率限制可能是合理的。强制执行 GraphQL API 的速率限制比 REST API 更为复杂,因为 GraphQL 操作的大小和复杂性差异很大,因此速率限制不能仅基于单个请求。 相反,我们不得不考虑操作在单个请求的上下文中可能遍历的图的比例。

对于 GraphQL API 实施速率限制没有一种通用的方法。例如,GitHub GraphQL API 设置了一个节点最大限制,以及一个基于查询中字段连接的评分点。然后它将这个评分点与每小时最大 5,000 个点的限制进行比较。

Shopify API,另一方面,为各种类型和连接字段分配不同的点值(同时还考虑连接字段返回的项目数量),并将由于通常消耗服务器资源而赋予突变操作较高的值。然后使用一个漏桶算法,以每秒50点(最多1,000点)的速率来适应客户端API流量的突然增加。

GitHub和Shopify的速率限制方法都涉及复杂的话题查询费用分析(也称为查询复杂性分析)。从这些例子中我们可以看出,为一个查询分配费用是复杂且多变的,应适合特定API的做法。在npm上存在几个与查询费用相关的包可以添加到,但在使用之前,请确保这些库为您做出的假设确实适用于您的API。

例如,您可能想为不同类型的节点设置固定成本,或者您可能通过使用指令(或者两种方法的组合)手动设置每类型或每字段的成本。您还可能对处理类型复杂度(返回请求的字段数所花费的成本)和响应复杂度(针对请求字段提供响应的成本)有不同的考虑。或者对于不显式计数类型和字段的全然不同的方法,您可以根据字段追踪数据设置并迭代查询成本,并为每个查询设置最大时间预算。

考虑到定制查询成本分析解决方案的潜在范围,您首先应验证您的API确实需要一个。对于仅由第一方客户端使用的,其他需求控制机制可能就足够了。如果您确实需要在您的GraphQL API中添加全面的查询成本分析,那么IBM在此领域所做的工作,即开发GraphQL 成本指令规范可能是有益的。他们的这项工作最初在论文中发表(附带补充视频以强调一些关键概念)在此系列博客文章中进一步探讨

路由器中的身份验证和授权

路由器中强制执行身份验证和授权可以保护您的底层API免受恶意查询的侵害。在您的supergraph的入口点丢弃未经验证的、未经授权的查询可以释放您的下游图形仅处理有效请求,从而降低负载并提高性能。

路由器中加固对您的supergraph的访问,添加零信任和多层次防御策略时也提供了另一层安全性。路由器集中身份验证和授权逻辑,下游服务可以通过自己的检查来加强。

为了在路由器中强制执行身份验证和授权:

批量请求

批量请求是恶意查询的另一种潜在攻击向量。有两种不同类型的批量攻击需要考虑。第一种威胁与GraphQL固有的“批量”请求的能力有关,允许在一个操作文档中包含多个根字段

query {
astronaut(id: "1") {
name
}
second: astronaut(id: "2") {
name
}
third: astronaut(id: "3") {
name
}
}

在没有任何限制的情况下,客户端可以有效地通过单个请求,如上述请求,遍历所有节点,同时跳过其他暴力保护措施。限制查询范围或使用查询成本分析可以帮助保护GraphQL API免受此类滥用。

当客户端在一个请求中发送多个完整的操作批处理时,这种批次形式也会发生,在某些场景下这有助于性能。路由器不支持这种批次形式。当操作被批处理时,Apollo Server收到一个操作数组,并将一个响应数组发送回客户端进行解析(在中存在直接的批量链接,以便方便处理):

[
{
operationName: "FirstAstronaut"
variables":{},
"query":"query FirstAstronaut {\n astronaut(id: \"1\") {\n name\n }\n}\n
},
{
operationName: "SecondAstronanut"
variables":{},
"query":"query SecondAstronanut {\n astronaut(id: \"2\") {\n name\n }\n}\n
},
{
operationName: "ThirdAstronaut"
variables":{},
"query":"query ThirdAstronaut {\n astronaut(id: \"3\") {\n name\n }\n}\n
}
]

对于批处理操作,考虑整个批处理可能对速率限制计算和查询成本分析的影响是非常重要的,以确保客户端无法通过竞争条件来规避速率限制。

最后,除了字段和操作的批处理,某些与 GraphQL 相关的批处理形式可以帮助缓解 DoS 攻击,并使你的 API 的整体性能更佳。即使在实现了深度限制后,GraphQL 查询也容易导致对后端数据源请求数量的指数级增长。DataLoaders是减少从单个操作上下文的解析函数中到后端数据源的请求数量的方法之一。

管理联盟的安全

除了保护你的 GraphQL API 免受恶意行为者的侵害并锁定私有数据外,你还需要一个窗口来查看你的 API 如何被使用(以及由谁使用),以加强你的 GraphQL 安全态势。这就是模式注册表和可观察性工具(例如那些由GraphOS提供的)发挥作用以帮助控制谁可以对 API 进行更改以及监控 API 使用情况并在出现问题时发送警报的地方。

了解谁在使用你的图(及其使用方式)

为了增强观察性工具收集的跟踪的实用性,要求每个客户端都必须标识自己并为每个它执行的操作指定一个名称是一种最佳实践。Apollo 客户端的网页和移动版本提供了设置客户端名称和版本的简单 API。这有助于你在 GraphOS 中通过客户端对跟踪和指标进行分段。其他 API 客户端可以通过手动设置请求头apollographql-client-nameapollographql-client-version来提供客户端意识。(作为额外的好处,客户端意识还有助于你在执行时确定可能受到你 API 中提出的中断性更改影响的客户端。)

此外,在GraphOS中追踪数据可以帮助您监控API性能和错误。您可以配置警报,在发生问题(如每分钟请求增加、p50、p95或p99响应时间变化或针对您的图形运行的操作错误)时将通知推送给您的团队。例如,关于错误百分比突然增加的通知可能表明有恶意行为者在尝试绕过已关闭的探针并通过快速猜测和测试不同的字段名称来了解更多关于图形架构的信息。如果您还希望在GraphOS之外利用错误数据,您还可以使用GraphOS RouterOpenTelemetry的支持来与其他APM工具集成。

限制对您的图形的写入访问

您应该像管理外部客户的通信一样仔细地管理对您supergraph的内部访问。GraphOS提供了图形API密钥和个人API密钥以限制组织内图形的访问。它还支持SSO集成和不同的成员角色,以便在团队成员参与时分配适当的权限。

除了成员角色之外,GraphOS还允许将某些指定为受保护的变体,以进一步限制谁能修改其架构,这在生产环境中尤为重要。

其他资源

有关GraphQL相关安全问题的进一步阅读,OWASPGraphQL快速参考表是帮助您审查图形安全状况的优秀资源。

下一节
首页
评价文章评价在GitHub上编辑编辑论坛Discord

©2024Apollo Graph Inc.,即Apollo GraphQL。

隐私政策

公司