-
Notifications
You must be signed in to change notification settings - Fork 25
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
fix(graphql): disable introspection endpoint on production #2098
Conversation
caluma/schema.py
Outdated
if settings.DISABLE_INTROSPECTION: | ||
validate = partial(validate, rules=(DisableIntrospection,)) | ||
|
||
validation_errors = validate( | ||
schema=schema.graphql_schema, | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not quite the right place to run the validation. This will run at startup, but you'll need to validate the actual GQL query coming in, not just the schema
The validate()
function (sadly, not a method) used is in graphql.validation.validate
, and uses a default list of rules from here: graphql.validation.specified_rules.specified_rules
. Unfortunately there doesn't appear to be a "right way" to add more rules.
But - even though I don't think it's meant to do that way, if we'd extend that list by adding the DisableIntrospection
rule, we'd probably get the desired effect.
Something like:
if settings.DISABLE_INTROSPECTION: | |
validate = partial(validate, rules=(DisableIntrospection,)) | |
validation_errors = validate( | |
schema=schema.graphql_schema, | |
) | |
if settings.DISABLE_INTROSPECTION: | |
from graphql.validation.specified_rules import specified_rules | |
specified_rules.append(DisableIntrospection) |
Sadly I don't see any better way right now to inject the rule as needed - feel free to dig deeper :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW the call traces along these lines:
caluma.caluma_user.views.AuthenticationGraphQLView.dispatch()
graphene_django.views.GraphQLView.dispatch()
graphene_django.views.GraphQLView.get_response()
graphene_django.views.GraphQLView.execute_graphql_request()
graphql.validation.validate.validate()
<-- this could accept the rules param, but it's not passed, so the default noted in the previous comment is used
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the review! My approach was a mix of this blobpost and the graphene doc
Otherwise we could implement it in the View by overwriting execute_graphql_request
?!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But your proposal of extending graphql.validation.specified_rules
looks also good!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the review! My approach was a mix of this blobpost and the graphene doc
The first example is just showing the calling conventions of the validate()
function.
Otherwise we could implement it in the View by overwriting
execute_graphql_request
?!
Indeed, the "correct" way would be to overload execute_graphql_request()
, but that contains a ton of code that we'd need to duplicate, just so we could then insert the correct call to validate()
. Seems excessive and problematic, as we'd need to keep track of the upstream implementation. Thus my suggestion of extending the specified_rules
.
After thinking about it some more, I think since this is only used for development mode, it's probably not too bad to mess with specified_rules
- if the implementation changes, we'd notice relatively quickly, which might not be the case in the other variant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, also note the way the blog post calls validate()
, they're replacing the whole rules
parameter with just one rule - so all the specified_rules
get disabled, which may allow malformed requests to penetrate much deeper into the code, possibly opening up a ton of security problems. Iff we go that route, we should at least do rules=specified_rules+[DisableIntrospection]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There seems to be an easier way in the making
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
graphene-django 3.2.0 is out now so we can utilize the latest feature to do the job. 🎉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't get it running locally with the new version. Could we have a small timed-boxed session @winged to hack this together?
0b39aca
to
2879aa8
Compare
disable introspection via validation rules property
2879aa8
to
e9f837b
Compare
Interface types, such as `Question`, `Answer`, and `Task` have subclasses, and connections using those types may return a mix of specific object types. Examples are form -> questions, which may return different question types. For these interface types, the `graphene` internals require access to a `FooType.Meta._meta.registry` property, to access the type registry. Somehow, the graphene metaclass system does not automatically build this up correctly, so we have to help a little bit to make it work
No description provided.