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

Improve Security of GraphiQL #508

Merged
merged 10 commits into from
Mar 16, 2019

Conversation

danpalmer
Copy link
Collaborator

@danpalmer danpalmer commented Aug 30, 2018

This PR makes the following security improvements to GraphiQL in graphene-django.

  • Stores the GraphQL query in the URL fragment, rather than the query, so that sensitive data won't be logged to web server logs.
  • Moves JS to a separate file to enable stricter Content Security Policies.

@@ -24,41 +24,13 @@
</head>
<body>
<script>

Copy link

@graingert graingert Aug 30, 2018

Choose a reason for hiding this comment

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

Strange whitespace change?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This was me "boyscouting" to make the code more readable, but I decided it was unnecessary when I re-did these changes.

@coveralls
Copy link

coveralls commented Aug 30, 2018

Coverage Status

Coverage decreased (-0.3%) to 94.405% when pulling 2b08e59 on danpalmer:graphiql-no-querystring into 9351626 on graphql-python:master.

@graingert
Copy link

Might be better to fill the query into the editor, and only execute it when the button is pressed.

A further security measure could be to use a warning dialogue for queries loaded from the URL when the submit button is pressed?

@graingert
Copy link

What about using a fragment instead?

@danpalmer
Copy link
Collaborator Author

Might be better to fill the query into the editor, and only execute it when the button is pressed.

A further security measure could be to use a warning dialogue for queries loaded from the URL when the submit button is pressed?

I think these are orthogonal concerns, but I will look into doing them.

What about using a fragment instead?

Good call, I will do this.

@danpalmer danpalmer force-pushed the graphiql-no-querystring branch from 58e7986 to 9a5b355 Compare August 30, 2018 18:48
@danpalmer
Copy link
Collaborator Author

@graingert can you re-review please. I think this implements everything you suggested, if I understood correctly. Also special cased browser refreshes so that you don't get prompted to allow the query if you're just refreshing the page (which I frequently do to refresh the schema).

@danpalmer danpalmer changed the title Don't put queries in the querystring Improve Security of GraphiQL Aug 30, 2018
@@ -41,7 +41,7 @@
});
// Produce a Location query string from a parameter object.

Choose a reason for hiding this comment

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

This comment isn't quite right anymore

var isReload = window.performance ? performance.navigation.type === 1 : false;
if (Object.keys(parameters).length
&& !isReload
&& !window.confirm("An untrusted query has been loaded, continue loading query?")) {

Choose a reason for hiding this comment

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

Might be worth including an explanation of why running an untrusted query might be a bad idea, and what damage it could cause.

Also something like "if you're not sure click cancel"

This is the Facebook devtools warning for eg:

Stop!

This is a browser feature intended for developers. If someone told you to copy and paste something here to enable a Facebook feature or "hack" someone's account, it is a scam and will give them access to your Facebook account.

See https://www.facebook.com/selfxss for more information.

@graingert
Copy link

Looks like handling untrusted input on submission will need changes in Graphiql

This also allows the introspection query through so that the user can
edit with intellisense before being prompted.
@danpalmer
Copy link
Collaborator Author

@graingert I'm not sure it will. I've updated with my implementation, although I'm not sure that it's perfect.

document.body
);
</script>
<script src="{% static "graphene_django/graphiql.js" %}"></script>
Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't this imply graphene_django relies on staticfiles now?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes. Do you think that needs documenting? I don’t know how optional it is in Django.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@danpalmer
Copy link
Collaborator Author

@syrusakbary could you take a look at this and let me know what you think?

For what it's worth, the main issue - GraphQL queries being in the URL query-string has bitten us and we'll probably have to disable GraphiQL if we can't find a way to improve the security.

@syrusakbary
Copy link
Member

syrusakbary commented Aug 31, 2018

Hey @danpalmer, thanks for the PR.

Thanks to the way the GraphQL view is architected, mutations will not be executed if the request is coming through a GET request (meaning: someone accessing an URL from the browser).
See code here: https://github.com/graphql-python/graphene-django/blob/master/graphene_django/views.py#L260-L263
However, query operations will be executed regardless (for both GET and POST HTTP verbs).

I think, rather than disabling eager GraphQL execution at all times, we can just have a flag like:

graphiql_eager_execution = True / False

That will indicate to execute the GraphQL query in GraphiQL eagerly or not.
We could make it True by default to not break old behaviour.

The code for the GraphQL view / GraphiQL integration is highly inspired by how graphql-express works. Demo of GraphiQL here: https://graphql.org/swapi-graphql/
That's why I'm a bit hesitant to go out of the norm for GraphQL/GraphiQL views, since all frameworks we have adopted a similar approach.

Thoughts?

@danpalmer
Copy link
Collaborator Author

@syrusakbary

Thanks to the way the GraphQL view is architected, mutations will not be executed if the request is coming through a GET request (meaning: someone accessing an URL from the browser).

Yeah I noticed this, it's a good decision. How about we always eagerly execute queries, and prompt the user for mutations. I think it's worth being clear about the untrusted nature of the mutations.

The code for the GraphQL view / GraphiQL integration is highly inspired by how graphql-express works. That's why I'm a bit hesitant to go out of the norm for GraphQL/GraphiQL views, since all frameworks we have adopted a similar approach.

Thanks for this, I'm not familiar with other implementations. I agree that we should try to work in a similar way, although I think the change to using a fragment rather than the query string to store the query is an important security feature - so a place where I think it's worth breaking away from their design.

we'll probably have to disable GraphiQL if we can't find a way to improve the security.

Also, apologies for this, I received feedback that it could be read as much more hostile than I intended. The query string change is necessary for us to start exposing GraphiQL to other developers internally, so I'm happy to make whatever changes are necessary for this to be merged.

The only security risk here is persuading a user to execute a mutation,
which is probably not a big risk. To mitigate this risk and still keep
the same UX (that is so valuable), would require more work than is
proportionate for this PR.
@danpalmer
Copy link
Collaborator Author

@syrusakbary thanks for all the feedback on this.

I've backed out the changes to query execution in GraphiQL for now as I think they need more thought, or just for the change to be made in GraphiQL itself.

Updated the PR description with the features this now implements. Would be great to get this reviewed and merged!

@syrusakbary
Copy link
Member

Great, will take a time to review it practically tomorrow :)

@jplock
Copy link

jplock commented Sep 9, 2018

This PR will make
#308 more difficult to implement. Is there anyway to combine them?

@danpalmer
Copy link
Collaborator Author

@jplock ah interesting, I don't think this should make it any more difficult to implement #308 – there will be a very minor merge conflict, but there are review points that need addressing that will cause a rewrite of those lines anyway, so I think I'm going to leave the changes for that PR.

@danpalmer
Copy link
Collaborator Author

Hey, quick ping on this. I believe all feedback has been addressed and that it's ready for merge.

@danpalmer
Copy link
Collaborator Author

@syrusakbary any update on this?

@danpalmer
Copy link
Collaborator Author

I believe this is ready to merge and that I've addressed all review points. If there's something outstanding here please let me know – I'm happy to address! Would be nice to get this merged soon though.

@danpalmer
Copy link
Collaborator Author

@jkimbo are you able to take a look and merge?

Copy link
Member

@jkimbo jkimbo left a comment

Choose a reason for hiding this comment

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

@danpalmer unfortunately I don't have write access so you'll have to wait on @syrusakbary

Code looks good though 👍

@danpalmer
Copy link
Collaborator Author

@syrusakbary ping on this. It's been hanging around for a while and I don't want it to bit rot. Also we're scaling up the number of devs working with GraphQL, so we would appreciate the security enhancements here (notably not logging the queries in webserver logs).

@danpalmer
Copy link
Collaborator Author

@syrusakbary @patrick91 @grantmcconnaughey @pizzapanther @spockNinja @RadoRado

Paging contributors. Apologies for the mentions but we've tried pinging and bumping this and haven't get anywhere so far.

It would be a real shame for graphene-django to bitrot and stop getting updates. We're investing heavily in it and would love to contribute, but PRs taking months to get merged discourages us from doing so.

This PR is good to go, it's been reviewed, all criticism so far has been addressed (sufficiently I believe). We're more than happy to fix any additional code review points, but otherwise it would be great to get clarity on why this isn't being merged, especially as it's addressing a security vulnerability.

@patrick91
Copy link
Member

I can approve but I don't have merge permissions, unfortunately

@danpalmer
Copy link
Collaborator Author

It seems like we have quite high bus factor on this repo. Who has merge permissions? Can they be extended to other frequent contributors like @patrick91 or @jkimbo?

@danpalmer
Copy link
Collaborator Author

@patrick91 it looks like you do have merge permissions? GitHub requires "1 approving review by reviewers with write access", and it's listing you under that.

@pizzapanther
Copy link
Contributor

Even if you have GitHub permission what about pypi to publish it?

@danpalmer
Copy link
Collaborator Author

@pizzapanther merging would at least prevent this PR from bitrotting and would allow people to target the master branch in their requirements if they really wanted to, so I think it would be an improvement, but yes PyPI access would be ideal.

@patrick91
Copy link
Member

@danpalmer this is what I get, even when there's other reviews from members of the org screenshot 2018-10-24 at 14 59 01

I can push to the repo, but not on master :)

@danpalmer
Copy link
Collaborator Author

Ah damn, sounds like GitHub PR review requirements and protected branches aren't fully compatible. Thanks for checking though!

@danpalmer
Copy link
Collaborator Author

@syrusakbary Ping on this. Would be good to talk about the process for PRs getting merged and releases getting shipped in the long run, it would be a real shame for this package to be unmaintained.

@syrusakbary
Copy link
Member

Hi @danpalmer, sorry for the long delay here.
I'm now very immersed in a new venture and takes almost all my time.

I'm working on laying out a plan for Graphene so things like this can be reviewed and merged without my explicit approval, and the project can continue growing at a healthy pace.

@pizzapanther
Copy link
Contributor

We should call the person who did flatmap-stream on npm. Think he likes to take over projects. 🤣

@patrick91
Copy link
Member

Hi @danpalmer, sorry for the long delay here.
I'm now very immersed in a new venture and takes almost all my time.

I'm working on laying out a plan for Graphene so things like this can be reviewed and merged without my explicit approval, and the project can continue growing at a healthy pace.

finally!

@syrusakbary
Copy link
Member

Ok, I'm starting to roll the plan.

Please take a look on the main issue in Graphene to provide input and feedback into how you think Graphene can be governed in the long term :)

graphql-python/graphene#884

@jkimbo jkimbo merged commit 297b807 into graphql-python:master Mar 16, 2019
@adamchainz
Copy link
Contributor

@jkimbo thanks!

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.

9 participants