跳到主要内容
博客计算保护您的 GraphQL 服务器,防止资源过度消耗

防止 GraphQL 服务器过度消耗资源

带有许多数据点的条形图插图,与文本一起形成波浪状外观:保护您的 GraphQL 服务器,防止过度消耗资源。

GraphQL 可以灵活地请求所需的资源和属性,不多也不少。这与 REST 不同,REST 经常会过度抓取或抓取不足数据。这种精确性使得 GraphQL 非常高效。此外,GraphQL 还提供了处理分页的标准方法,进一步提高了灵活性。不过,恶意用户可以利用这些 GraphQL 功能,这可能会给服务器的稳定性带来重大风险。

在本篇博客中,我们将探讨 GraphQL 的灵活性如何对您不利。我们将特别关注OWASP API 安全 Top 10 中强调的一个漏洞:无限制的资源消耗。我们还将讨论保护您的系统免遭此类滥用的实际步骤。

GraphQL 对过度抓取和抓取不足的回答

GraphQL 的设计部分是为了解决我们在使用 REST 时通常会遇到的过度抓取问题。例如,让我们考虑一个包含用户、产品和订单的标准电子商务数据库。想象一下,我们需要获取订单 ID 中的订单总金额。使用 REST,对 /orders/17 的 GET 请求不仅会获取金额,还会获取以下内容:

  • 订单数据
  • 账单信息
  • 运输信息
  • 产品数量
  • 税款
  • 订单状态
  • ...及更多

那是过度捕捉。

使用 REST 时,当您需要将多个资源中的相关数据拼凑在一起时,也会遇到抓取不足的问题。想象一下,您想显示一个摘要,其中包括订单的日期和状态、订单中所有产品的名称和描述,以及下订单用户的姓名和电子邮件地址。为此,您需要发送多个请求:

  • GET /orders/17
  • GET /products/1662527
  • GET /products/9914188
  • GET /products/3750021
  • GET /products/7557109
  • GET /products/6081142
  • GET /users/3314

GraphQL 可以解决 REST 的这些缺陷。您可以在相关资源中准确查询所需内容。要实现上述功能,您的 GraphQL 可能如下所示:

query {
  order(id: "17") {
    date
    status
    products {
      name
      description
    }
    user {
      name
      email
    }
  }
}

它是如此简单和灵活!不过,这种灵活性也意味着恶意用户可以故意过度获取数据。

滥用查询灵活性

GraphQL 的查询语法允许您在同一个请求中执行多个查询。我们可以使用上述查询执行类似的操作:

query {
  Q1: order(id: "17") {
    date
    status
    products {
      name
      description
    }
    user {
      name
      email
    }
  }
  Q2: order(id: "17") {
    date
    status
    products {
      name
      description
    }
    user {
      name
      email
    }
  }
}

这一次,我们请求的数据与上一次查询的数据相同,只不过我们请求了两次。自然,响应的大小将是单次查询请求的两倍。但是,如果我们在一次请求中重复查询 100 次呢?

query {
  Q00: order(id: "17") {    …  }  Q01: order(id: "17") {    …  }  …  Q99: order(id: "17") {    …  }
}

就这样,我们制作出了一个响应大小是原始查询 100 倍的查询。下面这张芝士汉堡的图片就是说明这种攻击的好方法。汉堡包构成了单个请求;但在汉堡包之间,可能有数百个牛肉饼!

填充查询

如果恶意用户滥用这种查询灵活性,过多的资源消耗可能会导致服务器瘫痪。

滥用分页功能

GraphQL 还有一些处理分页的标准方法。一种常见的方法是基于偏移量的分页,在这种方法中,调用者提供了要获取的条目的数量(限制)和要从哪个条目开始(偏移量)。

例如,从产品搜索中返回信息的查询可能如下所示:

query {
  products(searchString: "shirt", limit: 8, offset: 0) {
    id
    name
    description
    sku
    category
    images {
      path
      alt_text
    }
    variations {
      name
      description
      cost
    }
  }
}

如果我们调整分页参数来运行这个查询呢?

query {
  products(searchString: "shirt", limit: 800, offset: 0) {    …  }}

我在一个电子商务网站上测试了一组类似的示例,并对收到的回复进行了比较:

$ du response*.json
680496  response_big.json
333649  response_small.json

你可能会认为大文件的大小大约是小文件的 100 倍,因为限制设置为 800 而不是 8。 搜索可能没有产生 800 个结果(可能只有 16 到 20 个)。

滥用分页是另一个例子,说明有人可能会操纵 GraphQL 查询参数来增加服务器的负载。利用这一功能,攻击者可以迫使服务器处理比预期大得多的请求,从而可能导致资源耗尽和拒绝服务(DoS)。

OWASP API4:2023 不受限制的资源消耗

我们所演示的属于 OWASP API 安全十大漏洞,特别是API4:2023 不受限制的资源消耗。当应用程序接口不限制某些类型的交互或请求时,服务器就容易受到 DoS 攻击和其他操作中断的影响。

当应用程序接口允许无限制地过度查询或分页时,可能会导致资源消耗螺旋式上升。这反过来又会导致性能下降,甚至服务器完全瘫痪。如果没有适当的限制,这些攻击可能会中断服务。您可能会承担高昂的运营成本,看到客户离开,并失去业务。

如何保护自己

为应对这些风险,您需要适当规范 API 请求。实施控制,限制可请求的数据量。这包括设置查询大小和次数限制,以及实施速率限制和其他保护措施。

以下是一些保护自己的实用建议:

  • 请求和响应有效载荷大小限制:通过设置请求和返回数据的大小限制,可以防止过大的查询量压垮服务器。
  • 分页界限:为分页设置最大限制,确保调用者不会试图获取超过合理范围的记录。
  • 网络应用程序防火墙 (WAF):WAF 可以帮助检测和阻止恶意活动,挫败对 GraphQL API 的潜在攻击。考虑使用LinodeMarketplace 中的 Haltdos等 WAF 来添加额外的安全层。
  • API 安全工具:能够检测和减少恶意活动的工具至关重要。它们可以帮助识别可能预示着攻击的异常模式,使您能够在攻击影响系统之前采取行动。

通过采取这些步骤,您可以大大降低 GraphQL 服务器因过度消耗资源而被利用的风险。确保对 API 交互进行适当监管将有助于保持服务器的稳定性和性能。

有关使用 GraphQL 构建的更多信息,请查看我们文档中的GraphQL Apollo: 文档中的实例介绍

注释

留下回复

您的电子邮件地址将不会被公布。 必须填写的字段被标记为*