Skip to content

GraphQL Cheat Sheet / GraphQL速查表

Introduction / 介绍

GraphQL is an open source query language originally developed by Facebook that can be used to build APIs as an alternative to REST and SOAP. It has gained popularity since its inception in 2012 because of the native flexibility it offers to those building and calling the API. There are GraphQL servers and clients implemented in various languages. Many companies use GraphQL including GitHub, Credit Karma, Intuit, and PayPal.

This Cheat Sheet provides guidance on the various areas that need to be considered when working with GraphQL:

本速查表提供了在处理GraphQL时需要考虑的各个领域的指导:

  • Apply proper input validation checks on all incoming data.
    中文:对所有传入数据进行适当的输入验证检查。
  • Expensive queries will lead to Denial of Service (DoS), so add checks to limit or prevent queries that are too expensive.
    中文:昂贵的查询会导致[拒绝服务攻击(DoS)](Denial_of_Service_Cheat_Sheet.md),因此添加检查以限制或防止执行过于昂贵的查询。
  • Ensure that the API has proper access control checks.
    中文:确保API具有适当的访问控制检查。
  • Disable insecure default configurations (e.g. excessive errors, introspection, GraphiQL, etc.).
    中文:禁用不安全的默认配置(例如:过多的错误、内省、GraphiQL等)。

Common Attacks / 常见攻击

Best Practices and Recommendations / 最佳实践与建议

For the original security analysis, see Doyensec's GraphQL security overview.

关于原始安全分析,请参阅Doyensec的GraphQL安全概述。

Input Validation / 输入验证

Adding strict input validation can help prevent against injection and DoS. The main design for GraphQL is that the user supplies one or more identifiers and the backend has a number of data fetchers making HTTP, DB, or other calls using the given identifiers. This means that user input will be included in HTTP requests, DB queries, or other requests/calls which provides opportunity for injection that could lead to various injection attacks or DoS.

添加严格的输入验证可以帮助防止注入和DoS攻击。GraphQL的主要设计是用户提供一个或多个标识符,后端有多个数据检索器,使用这些标识符进行HTTP、数据库或其他调用。这意味着用户输入将包含在HTTP请求、数据库查询或其他请求/调用中,这为注入提供了机会,可能导致各种注入攻击或DoS攻击。

See the OWASP Cheat Sheets on Input Validation and general injection prevention for full details to best perform input validation and prevent injection.

请参阅OWASP的输入验证和注入预防备忘单,以获取有关如何执行最佳输入验证和防止注入的详细信息。

General Practices / 一般实践

Validate all incoming data to only allow valid values (i.e. allowlist).

验证所有传入数据,仅允许有效值(即白名单)。

Injection Prevention / 注入防护

When handling input meant to be passed to another interpreter (e.g. SQL/NoSQL/ORM, OS, LDAP, XML):

处理要传递给其他解释器(例如 SQL/NoSQL/ORM、操作系统、LDAP、XML)的输入时:

  • Always choose libraries/modules/packages offering safe APIs, such as parameterized statements.
    中文:始终选择提供安全 API 的库/模块/包,例如参数化语句。
    • Ensure that you follow the documentation so you are properly using the tool
      中文:确保您遵循文档说明,正确使用工具
    • Using ORMs and ODMs are a good option but they must be used properly to avoid flaws such as ORM injection.
      中文:使用 ORM 和 ODM 是一个好选择,但它们必须被正确使用,以避免诸如 ORM 注入 等缺陷。
  • If such tools are not available, always escape/encode input data according to best practices of the target interpreter
    中文:如果此类工具不可用,则始终根据目标解释器的最佳实践对输入数据进行转义/编码。
    • Choose a well-documented and actively maintained escaping/encoding library. Many languages and frameworks have this functionality built-in.
      中文:选择一个文档齐全且积极维护的转义/编码库。许多语言和框架都内置了此功能。

For more information see the below pages:

更多信息请参阅以下页面:

Process Validation / 进程验证

When using user input, even if sanitized and/or validated, it should not be used for certain purposes that would give a user control over data flow. For example, do not make an HTTP/resource request to a host that the user supplies (unless there is an absolute business need).

在使用用户输入时,即使经过清理和/或验证,也不应将其用于可能会让用户控制数据流的某些目的。例如,不要向用户提供的宿主发起HTTP/资源请求(除非有绝对的业务需求)。

DoS Prevention / DoS防护

DoS is an attack against the availability and stability of the API that can make it slow, unresponsive, or completely unavailable. This CS details several methods to limit the possibility of a DoS attack at the application level and other layers of the tech stack. There is also a CS dedicated to the topic of DoS.

DoS是对API可用性和稳定性的攻击,可能会使其变慢、无响应或完全不可用。此CS详细介绍了在应用层和其他技术栈层限制DoS攻击可能性的几种方法。还有一个CS专门针对DoS主题。

Here are recommendations specific to GraphQL to limit the potential for DoS:

以下是针对GraphQL的具体建议,以限制DoS的可能性:

  • Add depth limiting to incoming queries
    中文:为传入查询添加深度限制
  • Add amount limiting to incoming queries
    中文:为传入查询添加数量限制
  • Add pagination to limit the amount of data that can be returned in a single response
    中文:添加 分页 以限制单个响应中可以返回的数据量
  • Add reasonable timeouts at the application layer, infrastructure layer, or both
    中文:在应用层、基础设施层或两者中添加合理的超时时间
  • Consider performing query cost analysis and enforcing a maximum allowed cost per query
    中文:考虑执行查询成本分析并强制执行每个查询的最大允许成本
  • Enforce rate limiting on incoming requests per IP or user (or both) to prevent basic DoS attacks
    中文:对每个IP或用户(或两者)的传入请求执行速率限制,以防止基本的DoS攻击
  • Implement the batching and caching technique on the server-side (Facebook's DataLoader can be used for this)
    中文:在服务器端实现 批处理和缓存技术(可以使用 Facebook 的 DataLoader 来实现此功能)

Query Limiting (Depth & Amount) / 查询限制(深度与数量)

In GraphQL each query has a depth (e.g. nested objects) and each object requested in a query can have an amount specified (e.g. 99999999 of an object). By default these can both be unlimited which may lead to a DoS. You should set limits on depth and amount to prevent DoS, but this usually requires a small custom implementation as it is not natively supported by GraphQL. See this and this page for more information about these attacks and how to add depth and amount limiting. Adding pagination can also help performance.

在GraphQL中,每个查询都有一个深度(例如:嵌套对象)以及每个查询中请求的对象都可以指定数量(例如:99999999个对象)。默认情况下,这两个都可以设置为无限,这可能会导致DoS。您应该设置深度和数量的限制以防止DoS,但这通常需要一个小的自定义实现,因为GraphQL本身不支持这些功能。有关这些攻击的更多信息以及如何添加深度和数量限制,请参阅这篇和这篇页面。添加分页也可以帮助提高性能。

APIs using graphql-java can utilize the built-in MaxQueryDepthInstrumentation for depth limiting. APIs using JavaScript can use graphql-depth-limit to implement depth limiting and graphql-input-number to implement amount limiting.

使用graphql-java的API可以利用内置的MaxQueryDepthInstrumentation进行深度限制。使用JavaScript的API可以使用graphql-depth-limit来实现深度限制,并使用graphql-input-number来实现数量限制。

Here is an example of a GraphQL query with depth N:

这是一个深度为N的GraphQL查询示例:

query evil {            # Depth: 0
  album(id: 42) {       # Depth: 1
    songs {             # Depth: 2
      album {           # Depth: 3
        ...             # Depth: ...
        album {id: N}   # Depth: N
      }
    }
  }
}

Here is an example of a GraphQL query requesting 99999999 of an object:

这是一个请求99999999个对象的GraphQL查询示例:

query {
  author(id: "abc") {
    posts(first: 99999999) {
      title
    }
  }
}

Timeouts / 超时

Adding timeouts can be a simple way to limit how many resources any single request can consume. But timeouts are not always effective since they may not activate until a malicious query has already consumed excessive resources. Timeout requirements will differ by API and data fetching mechanism; there isn't one timeout value that will work across the board.

添加超时可以是一种简单的方式来限制单个请求可以消耗多少资源。但是,超时并不总是有效的,因为它们可能不会在恶意查询已经消耗了过多资源之前激活。超时要求将因API和数据获取机制而异;没有一个超时值可以在所有情况下都适用。

At the application level, timeouts can be added for queries and resolver functions. This option is usually more effective since the query/resolution can be stopped once the timeout is reached. GraphQL does not natively support query timeouts so custom code is required. See this blog post for more about using timeouts with GraphQL or the two examples below.

在应用层面,可以为查询和解析函数添加超时。这个选项通常更有效,因为一旦达到超时,查询/解析就可以停止。GraphQL本身不支持查询超时,因此需要自定义代码。有关如何在GraphQL中使用超时或以下两个示例的更多信息,请参阅这篇博客文章。

JavaScript Timeout Example

JavaScript超时示例

Code snippet from this SO answer:

代码片段来自这个SO答案:

request.incrementResolverCount =  function () {
    var runTime = Date.now() - startTime;
    if (runTime > 10000) {  // a timeout of 10 seconds
      if (request.logTimeoutError) {
        logger('ERROR', `Request ${request.uuid} query execution timeout`);
      }
      request.logTimeoutError = false;
      throw 'Query execution has timeout. Field resolution aborted';
    }
    this.resolverCount++;
  };

Java Timeout Example using Instrumentation

使用Instrumentation的Java超时示例

public class TimeoutInstrumentation extends SimpleInstrumentation {
    @Override
    public DataFetcher<?> instrumentDataFetcher(
            DataFetcher<?> dataFetcher, InstrumentationFieldFetchParameters parameters
    ) {
        return environment ->
            Observable.fromCallable(() -> dataFetcher.get(environment))
                .subscribeOn(Schedulers.computation())
                .timeout(10, TimeUnit.SECONDS)  // timeout of 10 seconds
                .blockingFirst();
    }
}

Infrastructure Timeout

基础设施超时

Another option to add a timeout that is usually easier is adding a timeout on an HTTP server (Apache/httpd, nginx), reverse proxy, or load balancer. However, infrastructure timeouts are often inaccurate and can be bypassed more easily than application-level ones.

另一种通常更容易实现的添加超时的方法是,在 HTTP 服务器(Apache/httpd,nginx),反向代理或负载均衡器上添加超时。然而,基础设施超时往往不够准确,并且比应用层超时更容易被绕过。

Query Cost Analysis / 查询成本分析

Query cost analysis involves assigning costs to the resolution of fields or types in incoming queries so that the server can reject queries that cost too much to run or will consume too many resources. This is not easy to implement and may not always be necessary but it is the most thorough approach to preventing DoS. See "Query Cost Analysis" in this blog post for more details on implementing this control.

查询成本分析涉及为传入查询中字段或类型的解析分配成本,以便服务器可以拒绝运行成本过高或将消耗过多资源的查询。这不容易实现,并且可能并不总是必要的,但它是最彻底的防止 DoS 的方法。有关实施此控制的更多详细信息,请参阅 这篇博客文章 中的“查询成本分析”。

Apollo recommends:

Apollo 推荐:

Before you go ahead and spend a ton of time implementing query cost analysis be certain you need it. Try to crash or slow down your staging API with a nasty query and see how far you get — maybe your API doesn’t have these kinds of nested relationships, or maybe it can handle fetching thousands of records at a time perfectly fine and doesn’t need query cost analysis!

中文:在您开始花费大量时间实现查询成本分析之前,请确保您确实需要它。 尝试使用一个恶意的查询来崩溃或减慢您的预发布 API,看看您能走多远——也许您的 API 没有这些类型的嵌套关系,或者它可以完美地处理一次获取数千条记录,并且不需要查询成本分析!

APIs using graphql-java can utilize the built-in MaxQueryComplexityInstrumentationto to enforce max query complexity. APIs using JavaScript can utilize graphql-cost-analysis or graphql-validation-complexity to enforce max query cost.

使用 graphql-java 的 API 可以利用内置的 MaxQueryComplexityInstrumentation 来强制执行最大查询复杂度。使用 JavaScript 的 API 可以利用 graphql-cost-analysis 或 graphql-validation-complexity 来强制执行最大查询成本。

Rate Limiting / 速率限制

Limit incoming HTTP requests per client using a request-rate control, such as Nginx's limit_req module. Apache's mod_ratelimit limits the transfer bandwidth of each response; it does not limit incoming request counts or aggregate traffic per client.

使用请求速率控制(如 Nginx 的 limit_req 模块)限制每个客户端的传入 HTTP 请求。Apache 的 mod_ratelimit 模块限制每个响应的传输带宽;它不限制传入请求数量或每个客户端的聚合流量。

HTTP request counts alone do not account for expensive queries or multiple operations in one request. Apply GraphQL rate limits in the business logic layer, together with query cost limits and batching limits.

仅凭 HTTP 请求次数无法衡量昂贵的查询或单个请求中的多次操作。在业务逻辑层应用 GraphQL 速率限制,并结合 查询成本限制 和 批处理限制。

Server-side Batching and Caching / 服务器端批处理和缓存

To increase efficiency of a GraphQL API and reduce its resource consumption, the batching and caching technique can be used to prevent making duplicate requests for pieces of data within a small time frame. Facebook's DataLoader tool is one way to implement this.

为了提高 GraphQL API 的效率并减少其资源消耗,可以使用 批处理和缓存技术 来防止在短时间内对数据片段进行重复请求。Facebook 的 DataLoader 工具是实现这一目标的一种方式。

System Resource Management / 系统资源管理

Not properly limiting the amount of resources your API can use (e.g. CPU or memory), may compromise your API responsiveness and availability, leaving it vulnerable to DoS attacks. Some limiting can be done at the operating system level.

未能合理限制 API 可以使用的资源数量(例如 CPU 或内存),可能会损害 API 的响应性和可用性,使其容易受到 DoS 攻击。一些限制可以在操作系统级别进行。

On Linux, a combination of Control Groups(cgroups), User Limits (ulimits), and Linux Containers (LXC) can be used.

在 Linux 上,可以使用 控制组(cgroups)、用户限制 (ulimits) 和 Linux 容器 (LXC) 的组合来实现。

However, containerization platforms tend to make this task much easier. See the resource limiting section in the Docker Security Cheat Sheet for how to prevent DoS when using containers.

然而,容器化平台往往使这项任务变得更加容易。参见 Docker 安全备忘录 中的资源限制部分,了解如何在使用容器时防止 DoS 攻击。

Access Control / 访问控制

To ensure that a GraphQL API has proper access control, do the following:

为确保 GraphQL API 具有适当的访问控制,请执行以下操作:

  • Always validate that the requester is authorized to view or mutate/modify the data they are requesting. This can be done with RBAC or other access control mechanisms.
    中文:始终验证请求者是否有权查看或修改他们请求的数据。这可以通过 RBAC 或其他访问控制机制来实现。
    • This will prevent IDOR issues, including both BOLA and BFLA.
      中文:这将防止 IDOR 问题,包括 BOLA 和 BFLA。
  • Enforce authorization checks on both edges and nodes (see example bug report where nodes did not have authorization checks but edges did).
    中文:在边和节点上强制执行授权检查(参见示例 bug report,其中节点没有授权检查,而边有)。
  • Use Interfaces and Unions to create structured, hierarchical data types which can be used to return more or fewer object properties, according to requester permissions.
    中文:使用 接口 和 联合 来创建结构化、分层的数据类型,可以根据请求者的权限返回更多或更少的对象属性。
  • Query and Mutation Resolvers can be used to perform access control validation, possibly using some RBAC middleware.
    中文:查询和突变 解析器 可以用于执行访问控制验证,可能需要使用一些基于 RBAC 的中间件。
  • Disable introspection queries) (禁用内省查询) system-wide in any production or publicly accessible environments.
  • Disable GraphiQL and other similar schema exploration tools in production or publicly accessible environments.
    中文:在生产环境或公开可访问的环境中,请禁用 GraphiQL 和其他类似的模式探索工具。

General Data Access / 通用数据访问

It's commonplace for GraphQL requests to include one or more direct IDs of objects in order to fetch or modify them. For example, a request for a certain picture may include the ID that is actually the primary key in the database for that picture. As with any request, the server must verify that the caller has access to the object they are requesting. But sometimes developers make the mistake of assuming that possession of the object's ID means the caller should have access. Failure to verify the requester's access in this case is called Broken Object Level Authentication, also known as IDOR.

在 GraphQL 请求中包含一个或多个对象的直接 ID 以获取或修改它们是很常见的。例如,请求某张图片时可能包含该图片在数据库中的实际主键 ID。与任何请求一样,服务器必须验证调用者是否有权访问他们请求的对象。但有时开发者会犯一个错误,认为拥有对象的 ID 就意味着调用者应该有权访问。在这种情况下未能验证请求者的访问权限被称为损坏的对象级身份验证,也称为IDOR。

It's possible for a GraphQL API to support access to objects using their ID even if that is not intended. Sometimes there are node or nodes or both fields in a query object, and these can be used to access objects directly by ID. You can check whether your schema has these fields by running this on the command-line (assuming that schema.json contains your GraphQL schema): cat schema.json | jq ".data.__schema.types[] | select(.name==\"Query\") | .fields[] | .name" | grep node. Removing these fields from the schema should disable the functionality, but you should always apply proper authorization checks to verify the caller has access to the object they are requesting.

即使不是有意为之,GraphQL API 也可能支持通过 ID 访问对象。有时查询对象中存在 node 或 nodes 或两者都有的字段,并且可以通过 ID 直接访问对象。您可以通过在命令行中运行以下命令来检查您的模式是否具有这些字段(假设 schema.json 包含您的 GraphQL 模式):cat schema.json | jq ".data.__schema.types[] | select(.name==\"Query\") | .fields[] | .name" | grep node。从模式中删除这些字段应禁用该功能,但您始终应应用适当的授权检查以验证调用者是否有权访问他们请求的对象。

Query Access (Data Fetching) / 查询访问(数据获取)

Detectify's New Relic disclosure) (Detectify 的 New Relic 揭示) illustrates why field access must respect account permissions.

As part of a GraphQL API there will be various data fields that can be returned. One thing to consider is if you want different levels of access around these fields. For example, you may only want certain consumers to be able to fetch certain data fields rather than allowing all consumers to be able to retrieve all available fields. This can be done by adding a check in the code to ensure that the requester should be able to read a field they are trying to fetch.

作为 GraphQL API 的一部分,将会有各种可以返回的数据字段。需要考虑的一点是您是否希望围绕这些字段有不同的访问级别。例如,您可能只想让某些消费者能够获取某些数据字段,而不是允许所有消费者能够检索所有可用的字段。这可以通过在代码中添加检查来实现,以确保请求者能够读取他们试图获取的字段。

Mutation Access (Data Manipulation) / 突变访问(数据操纵)

For an original case study, see Pen Test Partners' WordPress GraphQL disclosure.

有关原始案例研究,请参阅Pen Test Partners的WordPress GraphQL披露。

GraphQL supports mutation, or manipulation of data, in addition to its most common use case of data fetching. If an API implements/allows mutation then there may need to be access controls put in place to restrict which consumers, if any, can modify data through the API. Setups that require mutation access control would include APIs where only read access is intended for requesters or where only certain parties should be able to modify certain fields.

GraphQL支持突变,即数据的操纵,除了其最常见的数据获取用例。如果一个API实现/允许突变,那么可能需要实施访问控制,以限制哪些消费者(如果有的话)可以通过API修改数据。需要突变访问控制的环境包括仅对请求者提供读取访问的API,或者只有某些方能够修改某些字段的环境。

Batching Attacks / 批量攻击

GraphQL supports batching requests, also known as query batching. This lets callers to either batch multiple queries or batch requests for multiple object instances in a single network call, which allows for what is called a batching attack. This is a form of brute force attack, specific to GraphQL, that usually allows for faster and less detectable exploits. Here is the most common way to do query batching:

GraphQL支持批量请求,也称为查询批量处理。这允许调用者批量多个查询或批量请求多个对象实例的单个网络调用,从而允许所谓的批量攻击。这是一种针对GraphQL的暴力攻击形式,通常允许更快且更难检测的利用。以下是进行查询批量处理的最常见方式:

[
  {
    query: < query 0 >,
    variables: < variables for query 0 >,
  },
  {
    query: < query 1 >,
    variables: < variables for query 1 >,
  },
  {
    query: < query n >
    variables: < variables for query n >,
  }
]

And here is an example query of a single batched GraphQL call requesting multiple different instances of the droid object:

以下是一个单次批量GraphQL调用的查询示例,请求多个不同的droid对象实例:

query {
  droid(id: "2000") {
    name
  }
  second:droid(id: "2001") {
    name
  }
  third:droid(id: "2002") {
    name
  }
}

In this case it could be used to enumerate every possible droid object that is stored on the server in very few network requests as opposed to a standard REST API where the requester would need to submit a different network request for every different droid ID they want to request. This type of attack can lead to the following issues:

在这种情况下,它可以用来在非常少的网络请求中枚举服务器上存储的每个可能的droid对象,而不是在标准REST API中,请求者需要为每个他们想要请求的不同droid ID提交不同的网络请求。这种攻击可能导致以下问题:

  • Application-level DoS attacks - A high number of queries or object requests in a single network call could cause a database to hang or exhaust other available resources (e.g. memory, CPU, downstream services).
    中文:应用层DoS攻击 - 单个网络调用中的大量查询或对象请求可能导致数据库挂起或耗尽其他可用资源(例如内存、CPU、下游服务)。
  • Enumeration of objects on the server, such as users, emails, and user IDs.
    中文:服务器上对象的枚举,例如用户、电子邮件和用户ID
  • Brute forcing passwords, 2 factor authentication codes (OTPs), session tokens, or other sensitive values.
    中文:暴力破解密码、双因素认证码(OTPs)、会话令牌或其他敏感值
  • WAFs, RASPs, IDS/IPS, SIEMs, or other security tooling will likely not detect these attacks since they only appear to be one single request rather than an a massive amount of network traffic.
    中文:WAFs、RASPs、IDS/IPS、SIEMs 或其他安全工具可能无法检测这些攻击,因为它们看起来只是一个单独的请求,而不是大量的网络流量。
  • This attack will likely bypass existing rate limits in tools like Nginx or other proxies/gateways since they rely on looking at the raw number of requests.
    中文:这种攻击可能会绕过 Nginx 或其他代理/网关中现有的速率限制,因为它们依赖于查看原始请求数量。

Mitigating Batching Attacks / 缓解批量攻击

In order to mitigate this type of attack you should put limits on incoming requests at the code level so that they can be applied per request. There are 3 main options:

为了缓解此类攻击,您应该在代码级别对传入请求设置限制,以便它们可以按请求应用。主要有以下3个选项:

  • Add object request rate limiting in code
    中文:在代码中添加对象请求速率限制
  • Prevent batching for sensitive objects
    中文:防止敏感对象的批量处理
  • Limit the number of queries that can run at one time
    中文:限制一次可以运行的查询数量

One option is to create a code-level rate limit on how many objects that callers can request. This means the backend would track how many different object instances the caller has requested, so that they will be blocked after requesting too many objects even if they batch the object requests in a single network call. This replicates a network-level rate limit that a WAF or other tool would do.

一个选项是创建一个代码级别的速率限制,限制调用者可以请求的对象数量。这意味着后端会跟踪调用者请求了多少个不同的对象实例,因此即使他们在单个网络调用中批量请求对象,请求过多对象后也会被阻止。这类似于WAF或其他工具在网络级别执行的速率限制。

Another option is to prevent batching for sensitive objects that you don't want to be brute forced, such as usernames, emails, passwords, OTPs, session tokens, etc. This way an attacker is forced to attack the API like a REST API and make a different network call per object instance. This is not supported natively so it will require a custom solution. However once this control is put in place other standard controls will function normally to help prevent any brute forcing.

另一个选项是防止对敏感对象进行批处理,例如您不希望被暴力破解的用户名、电子邮件、密码、OTP、会话令牌等。这样攻击者被迫像REST API一样攻击API,并为每个对象实例进行不同的网络调用。这并不是原生支持的,因此需要自定义解决方案。然而,一旦这种控制措施到位,其他标准控制措施将正常工作,以帮助防止任何暴力破解攻击。

Limiting the number of operations that can be batched and run at once is another option to mitigate GraphQL batching attacks leading to DoS. This is not a silver bullet though and should be used in conjunction with other methods.

限制一次可以批处理和运行的操作数量是另一种缓解GraphQL批处理攻击导致DoS的方法。但这并不是万能的解决方案,应该与其他方法结合使用。

Secure Configurations / 安全配置

By default, most GraphQL implementations have some insecure default configurations which should be changed:

默认情况下,大多数GraphQL实现都有一些不安全的默认配置,应该进行更改:

  • Don't return excessive error messages (e.g. disable stack traces and debug mode).
    中文:不要返回过多的错误消息(例如,禁用堆栈跟踪和调试模式)。
  • Disable or restrict Introspection and GraphiQL based on your needs.
    中文:根据需要禁用或限制Introspection和GraphiQL。
  • Suggestion of mis-typed fields if the introspection is disabled
    中文:如果禁用Introspection,则建议误拼字段

Introspection + GraphiQL

GraphQL Often comes by default with introspection and/or GraphiQL enabled and not requiring authentication. This allows the consumer of your API to learn everything about your API, schemas, mutations, deprecated fields and sometimes unwanted "private fields".

GraphQL通常默认启用自省和/或GraphiQL,且无需身份验证。这允许API的消费者了解有关您的API、模式、突变、已弃用字段以及有时不希望出现的“私有字段”的所有信息。

This might be an intended configuration if your API is designed to be consumed by external clients, but can also be an issue if the API was designed to be used internally only. Although security by obscurity is not recommended, it might be a good idea to consider removing the Introspection to avoid any leak. If your API is publicly consumed, you might want to consider disabling it for not authenticated or unauthorized users.

这可能是一种有意为之的配置,如果您的API旨在由外部客户端使用,但也可能是一个问题,如果API仅设计用于内部使用。尽管隐蔽性安全不被推荐,但考虑移除自省以避免任何泄露可能是个好主意。如果您的API是公开使用的,您可能希望考虑为未认证或未经授权的用户禁用自省。

For internal API, the easiest approach is to just disable introspection system-wide. See this page or consult your GraphQL implementation's documentation to learn how to disable introspection altogether. If your implementation does not natively support disabling introspection or if you would like to allow some consumers/roles to have this access, you can build a filter in your service to only allow approved consumers to access the introspection system.

对于内部API,最简单的方法是全局禁用自省。参见这个页面或咨询您的GraphQL实现文档,了解如何完全禁用自省。如果您的实现不支持本地禁用自省,或者您希望允许某些消费者/角色拥有这种访问权限,您可以在服务中构建一个过滤器,仅允许经过批准的消费者访问自省系统。

Keep in mind that even if introspection is disabled, attackers can still guess fields by brute forcing them. Furthermore, GraphQL has a built-in feature to return a hint when a field name that the requester provides is similar (but incorrect) to an existing field (e.g. request has usr and the response will ask Did you mean "user?"). You should consider disabling this feature if you have disabled the introspection, to decrease the exposure, but not all implementations of GraphQL support doing so. Shapeshifter is one tool that should be able to do this.

请注意,即使禁用了自省,攻击者仍然可以通过暴力破解来猜测字段。此外,GraphQL有一个内置功能,当请求者提供的字段名与现有字段相似(但不正确)时,会返回一个提示(例如,请求有usr,而响应会询问“你是指'user'吗?”)。如果您已禁用自省,考虑禁用此功能以减少暴露,但并非所有GraphQL的实现都支持这样做。Shapeshifter是能够做到这一点的工具之一。Shapeshifter。

Disable Introspection - Java

禁用自省 - Java

GraphQLSchema schema = GraphQLSchema.newSchema()
    .query(StarWarsSchema.queryType)
    .fieldVisibility( NoIntrospectionGraphqlFieldVisibility.NO_INTROSPECTION_FIELD_VISIBILITY )
    .build();

Disable Introspection & GraphiQL - JavaScript

禁用自省 & GraphiQL - JavaScript

For existing applications using the deprecated express-graphql middleware, this illustration assumes NoIntrospection is an imported introspection-denying validation rule. Use a maintained server implementation for new applications.

对于使用已弃用的express-graphql中间件(https://github.com/graphql/express-graphql#this-library-is-deprecated)的现有应用程序,此说明假定NoIntrospection是一个导入的自省拒绝验证规则。对于新应用程序,请使用维护良好的服务器实现。

app.use('/graphql', graphqlHTTP({
  schema: MySessionAwareGraphQLSchema,
  validationRules: [NoIntrospection],
  graphiql: process.env.NODE_ENV === 'development',
}));

Don't Return Excessive Errors / 不要返回过多的错误

GraphQL APIs in production shouldn't return stack traces or be in debug mode. Doing this is implementation specific, but using middleware is one popular way to have better control over errors the server returns. To omit stack traces with Apollo Server, pass includeStacktraceInErrorResponses: false to its constructor. When this option is unspecified, NODE_ENV=production or NODE_ENV=test suppresses stack traces by default; error messages still require separate masking. However, if you would like to log the stack trace internally without returning it to the user see here for how to mask and log errors so they are available to the developers but not callers of the API.

生产环境中的 GraphQL API 不应返回堆栈跟踪或处于调试模式。这样做是具体实现的,但使用中间件是更好地控制服务器返回的错误的一种流行方式。要在 Apollo Server 中省略堆栈跟踪,将其构造函数中的 includeStacktraceInErrorResponses 设置为 false。当此选项未指定时,NODE_ENV=production 或 NODE_ENV=test 默认会抑制堆栈跟踪;错误消息仍需要单独屏蔽。然而,如果您希望在内部分录堆栈跟踪而不将其返回给用户,请参阅此处了解如何屏蔽和记录错误,以便它们可供开发者访问,但不可供 API 的调用者访问。

References / 参考