Vendure: GraphQL API rate/complexity limits

Created on 18 Jun 2020  路  3Comments  路  Source: vendure-ecommerce/vendure

Is your feature request related to a problem? Please describe.
Due to the flexible nature of GraphQL, it is possible to create queries that end up being very expensive for the server to execute, for example:

{
  products(options: { take: 1}) {
    items {
      facetValues {
        id
        facet {
          values {
            facet {
              values {
                facet {
                  values {
                    facet {
                      id
                      name 
                      translations {
                        id
                        languageCode
                        name
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

The above query takes 15 seconds to resolve on my fairly beefy laptop (and also returns a 825kb response)

Imagine now we have take: 100 rather than take: 1. There goes the whole server!

So the problem comes down to 2 potential risks:

  1. Poor performance due to accidentally-expensive queries by the developer
  2. Malicious attacks used to cause a denial-of-service by overwhelming the server with a request like the one above.

Describe the solution you'd like
There several strategies to mitigate these risks, which are well-described in this StackOverflow answer and thread.

Also see suggestions here: https://github.com/apollographql/apollo-server/issues/1310

The measures range from fairly simple (timeouts) to more complex, e.g. analyzing individual queries to compute a complexity score.

This thread will track further research into the topic and proposals on what to build in to Vendure core to give at least _some_ protection from the above by default.

@vendurcore security 馃攼

Most helpful comment

graphql-query-complexity looks to be a good solution for limiting too-deeply-nested queries. It looks well-maintained, only has 1 tiny dependency, and is quite widely downloaded on npm (80k / week)

There is an example here of integrating it with Apollo Server 2 as an ApolloServerPlugin

We could build a similar plugin and ship it with core, and users can import it as needed. It would have to be well-documented in the "deployment" docs as a recommendation for production deploys.

All 3 comments

graphql-query-complexity looks to be a good solution for limiting too-deeply-nested queries. It looks well-maintained, only has 1 tiny dependency, and is quite widely downloaded on npm (80k / week)

There is an example here of integrating it with Apollo Server 2 as an ApolloServerPlugin

We could build a similar plugin and ship it with core, and users can import it as needed. It would have to be well-documented in the "deployment" docs as a recommendation for production deploys.

For rate-limiting and timeouts we can make use of the vast Express ecosystem, since Vendure allows you to plug in any Express middleware quite trivially.

So now I'm thinking it makes sense to keep all of this out of core, and instead have a separate "production-ready" plugin which configures things like:

  • Rate limiting (e.g. https://www.npmjs.com/package/express-rate-limit)
  • Request timeouts (e.g. as discussed in https://github.com/expressjs/express/issues/3330)
  • query cost analysis as in the above comment
  • Possibly also perf enhancements such as query caching

Added docs on this for now, and will defer any other implementation to a later point.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

lsimone picture lsimone  路  7Comments

rrubio picture rrubio  路  5Comments

villesau picture villesau  路  3Comments

jonyw4 picture jonyw4  路  6Comments

stefanvanherwijnen picture stefanvanherwijnen  路  5Comments