PHP 7.3 reaches end of support in December 2021 and Adobe Commerce 2.3.x reaches end of support in April 2022. You may want to consider planning your upgrade now to Adobe Commerce 2.4.x and PHP 7.4.x to help maintain PCI compliance.

GraphQL security configuration

The Framework and GraphQl module di.xml files define several security-related configuration values that you should review to ensure they align with types of mutations and queries that you run.

To override these default values, create a custom module and provide a new value in the appropriate di.xml file.

Framework configuration

In GraphQL, the SearchCriteriaValidator class constructor limits the maximum page size in queries to 300 by default as well. You can change the default in the di.xml file. The following example changes the limit to 100:

1
2
3
4
5
<type name="Magento\Framework\GraphQl\Query\Resolver\Argument\Validator\SearchCriteriaValidator">
    <arguments>
        <argument name="maxPageSize" xsi:type="number">100</argument>
    </arguments>
</type>

API security describes additional arguments that are applicable to web APIs in general.

GraphQl module configuration

The GraphQl/etc/di.xml file contains two arguments that can be overridden to enhance security and prevent performance bottlenecks:

Attribute Default value Description
queryComplexity 300 Defines the maximum number of fields, objects, and fragments that a query can contain.
queryDepth 20 Defines the maximum depth of nodes that query can return.

Query complexity

A complex GraphQL query, such as the cart or products query, can potentially generate a heavy workload on the server. Complex queries can potentially be used to create distributed denial of service (DDoS) attacks by overloading the server with specious requests.

Each instance of the following items adds 1 to the complexity score:

  • A field and parent field in the body of the query.
  • A field in an inline fragment.
  • A field in a fragment spread. If a fragment spread is used multiple times, each field within is counted that number of times.

The following items do not count toward the complexity score:

  • The root query field
  • Fragment declarations
  • Fragment spread declarations

The following sample query contains all of the items listed above.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
query {
  countries {
    full_name_english
    name1: full_name_english
    ...on Country {
        two_letter_abbreviation
    }
    ...myFrag
    ...myFrag
  }
}
fragment myFrag on Country {
    three_letter_abbreviation
}

The complexity count for the query is 6. These lines contributed to the count:

  • countries {}
  • full_name_english (first instance)
  • name1: full_name_english
  • two_letter_abbreviation
  • three_letter_abbreviation (first instance of ...myFrag)
  • three_letter_abbreviation (second instance of ...myFrag)

Creating the name1 alias did not cause the system to double count the entry.

If the count does not exceed the threshold set by the queryComplexity attribute, Magento validates and processes the query.

Query depth

The queryDepth attribute specifies the maximum depth a query can return. This can be an issue for queries that return objects that show a hierarchy, such as CategoryTree, or queries that return detailed data on complex products. The default value of 20 allows for deep hierarchies and products, but you might want to reduce this number if you know that legitimate queries will never reach that depth.

The following query has a maximum depth of 5.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
{
  categories(
    filters: {
      parent_id: {in: ["2"]}
    }
  ) {
    total_count
    items {
      uid
      level
      name
      path
      children_count
      children {
        uid
        level
        name
        path
        children_count
        children {
          uid
          level
          name
          path
          children_count
          children {
            uid
            level
            name
            path
          }
        }
      }
    }
    page_info {
      current_page
      page_size
      total_pages
    }
  }
}

These fields contribute to the depth:

  • items
  • children (first instance)
  • children (second instance)
  • children (third instance)
  • uid and other fields in this node

If the depth of the query exceeds the value queryDepth, the system returns an error.