Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Limit the depth of introspection queries #6601

Merged
merged 14 commits into from
Jan 27, 2025
Merged

Conversation

SimonSapin
Copy link
Contributor

@SimonSapin SimonSapin commented Jan 21, 2025

The schema-intropsection schema is recursive: a client can query the fields of the types of some other fields, and so on arbitrarily deep. This can produce responses that grow much faster than the size of the request.

To protect against abusive requests Router now refuses to execute introspection queries that nest list fields too deep and returns an error instead. The criteria matches MaxIntrospectionDepthRule in graphql-js, but may change in future versions.

In case it rejects legitimate queries, this check can be disabled in Router configuration:

# Do not enable introspection in production!
supergraph:
  introspection: true  # Without this, schema introspection is entirely disabled by default
limits:
  introspection_max_depth: false  # Defaults to true

Checklist

Complete the checklist (and note appropriate exceptions) before the PR is marked ready-for-review.

  • Changes are compatible1
  • Documentation2 completed
  • Performance impact assessed and acceptable
  • Tests added and passing3
    • Unit Tests
    • Integration Tests
    • Manual Tests

Exceptions

Note any exceptions here

Notes

Footnotes

  1. It may be appropriate to bring upcoming changes to the attention of other (impacted) groups. Please endeavour to do this before seeking PR approval. The mechanism for doing this will vary considerably, so use your judgement as to how and when to do this.

  2. Configuration is an important part of many changes. Where applicable please try to document configuration examples.

  3. Tick whichever testing boxes are applicable. If you are adding Manual Tests, please document the manual testing (extensively) in the Exceptions.

The [schema-intropsection schema](https://spec.graphql.org/draft/#sec-Schema-Introspection.Schema-Introspection-Schema)
is recursive: a client can query the fields of the types of some other fields,
and so on arbitrarily deep.
This can produce responses that grow much faster than the size of the request.

To protect against abusive Router now refuses to execute introspection queries
that nest list fields too deep and returns an error instead.
The criteria matches `MaxIntrospectionDepthRule` in graphql-js,
but may change in future versions.

In case it rejects legitimate queries,
this check can be disabled in Router configuration:

```yaml
supergraph:
  introspection: true  # Needed to enable schema introspection in the first place
  introspection_check_max_depth: false  # Defaults to true
```
@SimonSapin SimonSapin requested review from a team as code owners January 21, 2025 10:31
@svc-apollo-docs
Copy link
Collaborator

svc-apollo-docs commented Jan 21, 2025

✅ Docs preview ready

The preview is ready to be viewed. View the preview

File Changes

0 new, 1 changed, 0 removed
* graphos/reference/migration/from-router-v1.mdx

Build ID: 5f350051025f52f7c176ee7a

URL: https://www.apollographql.com/docs/deploy-preview/5f350051025f52f7c176ee7a

This comment has been minimized.

@router-perf
Copy link

router-perf bot commented Jan 21, 2025

CI performance tests

  • connectors-const - Connectors stress test that runs with a constant number of users
  • const - Basic stress test that runs with a constant number of users
  • demand-control-instrumented - A copy of the step test, but with demand control monitoring and metrics enabled
  • demand-control-uninstrumented - A copy of the step test, but with demand control monitoring enabled
  • enhanced-signature - Enhanced signature enabled
  • events - Stress test for events with a lot of users and deduplication ENABLED
  • events_big_cap_high_rate - Stress test for events with a lot of users, deduplication enabled and high rate event with a big queue capacity
  • events_big_cap_high_rate_callback - Stress test for events with a lot of users, deduplication enabled and high rate event with a big queue capacity using callback mode
  • events_callback - Stress test for events with a lot of users and deduplication ENABLED in callback mode
  • events_without_dedup - Stress test for events with a lot of users and deduplication DISABLED
  • events_without_dedup_callback - Stress test for events with a lot of users and deduplication DISABLED using callback mode
  • extended-reference-mode - Extended reference mode enabled
  • large-request - Stress test with a 1 MB request payload
  • no-tracing - Basic stress test, no tracing
  • reload - Reload test over a long period of time at a constant rate of users
  • step-jemalloc-tuning - Clone of the basic stress test for jemalloc tuning
  • step-local-metrics - Field stats that are generated from the router rather than FTV1
  • step-with-prometheus - A copy of the step test with the Prometheus metrics exporter enabled
  • step - Basic stress test that steps up the number of users over time
  • xlarge-request - Stress test with 10 MB request payload
  • xxlarge-request - Stress test with 100 MB request payload

@SimonSapin SimonSapin requested a review from a team as a code owner January 21, 2025 10:33
Copy link
Member

@goto-bus-stop goto-bus-stop left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, should we also mention it in the migration guide?

.changesets/breaking_simon_introspection_max_depth.md Outdated Show resolved Hide resolved
Copy link
Member

@lrlna lrlna left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is handled a little bit differently than our existing limits, and I am torn on whether it should be handled in a similar fashion. On one hand, it's definitely a limit configuration, but on the other hand, it's specific to graphql specification, and is closely tied to introspection implementation itself, which will make it hard to decouple the limiting functionality from introspection itself.

The one thing we do have to think about is the error we return regardless of where the actual limiting lives. Is there merit to returning the same http::StatusCode::PAYLOAD_TOO_LARGE error as the other limits do?

Comment on lines 630 to 634
/// Limit the depth of nested list fields in introspection queries
/// to protect avoid generating huge responses.
/// Default: false
pub(crate) introspection_check_max_depth: bool,

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering if this should go here or under Limits config instead? It feels more of a limit, rather than a general supergraph configuration.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

apollo-router/src/introspection.rs Show resolved Hide resolved
@SimonSapin
Copy link
Contributor Author

should we also mention it in the migration guide?

Before this comment I didn’t realize we have this guide already. I’ve added to it now.

@SimonSapin SimonSapin enabled auto-merge (squash) January 27, 2025 15:26
@SimonSapin SimonSapin merged commit cbe4c32 into dev Jan 27, 2025
15 checks passed
@SimonSapin SimonSapin deleted the simon/introspection-max-depth branch January 27, 2025 16:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants