Lesson 20 / 25
Query Cost, Depth Limits and Persisted Queries
Protecting the server.
Bound what clients can ask for
Because clients compose queries, a single request can be very expensive: deeply nested relationships, huge page sizes or many aliased copies of a field. Protect the server with maximum depth, query complexity/cost analysis (assign costs to fields and multiply by page sizes), maximum page sizes, timeouts and rate limits based on cost. Persisted queries go further: clients send a hash or ID of a pre-registered operation, and the server can reject unknown queries entirely, which suits first-party apps.
An expensive query and the defences
Why limits matter.
# without limits, this asks for up to 100 x 100 x 100 = 1,000,000 nodes
query Expensive {
users(first: 100) {
edges { node {
followers(first: 100) {
edges { node {
followers(first: 100) { edges { node { name } } }
} }
}
} }
}
}
# defences: depth limit (e.g. 7), cost limit (e.g. 1,000 points with list sizes multiplied),
# max first: 50, request timeout, persisted query allow-list for first-party clientsAlso limit aliases and batching
Attackers can repeat a field hundreds of times with aliases or send many operations in one batch to bypass simple rate limits.
Quick check: What do persisted queries allow a server to do?
- Skip the schema entirely
- Accept only pre-registered operations, identified by hash or ID
- Store user passwords
- Disable resolvers
Answer
Accept only pre-registered operations, identified by hash or ID — An allow-list of queries.