Comments (11)
Sorry for taking so long to get back to this. Yes, I think it would be reasonable for me to write a PR for this.
The key bit to me is that CSRF has become a much simpler problem to avoid in the modern REST/JSON API world, because API endpoints that require you to pass Content-Type: application/json
for any request with side effects are automatically protected against CSRF. In fact, developers these days often don't even have to learn about CSRF as long as all the APIs they create have that property.
Because of this, my first suggestion will be that we change the POST section
If the client does not supply a
Content-Type
header with a POST request, the
server SHOULD reject the request using the appropriate4xx
status code.
from a SHOULD to a MUST. Do we know of any real GraphQL servers that don't already obey this?
Secondly, I would add a non-normative section noting that GraphQL servers are generally immune to CSRF attacks, because side effects should only be accessible through mutations, mutations can only be executed by POSTs, and POST requests MUST have an appropriate Content-Type
header. However, if a GraphQL server chooses to allow POSTs with non-officially-recognized Content-Type
headers, and specifically the Content-Type
of multipart/form-data
(or text/plain
or application/x-www-form-urlencoded
), then suddenly the immunity to CSRF attacks will vanish. If immunity from CSRF attacks matters (eg, you have a web client that uses cookies or Basic Auth, or your web server is not accessible on the public internet and gives extra trust to any client that can contact it), you should avoid allowing those Content-Type
s or provide an alternative CSRF prevention method such as requiring all such requests to have a require-preflight
header.
Thirdly, I would consider noting that even allowing read-only GET requests from web browser clients without CORS preflighting can be problematic, due to timing attacks. It may be reasonable for most REST GET APIs to be accessible without a CORS preflight, because the only information code from a non-allowed origin can learn is how long the API took, and it's often not too hard to make the response time of a normal REST GET API relatively constant. But GraphQL queries are very flexible, and it's quite possible to design a query that can use timing to determine whether a given field returns null or not, by nesting under that field a complex set of recursive field selections that are only evaluated if the field returns non-null. So a non-normative suggestion that servers that use cookies/Basic Auth or are inaccessible from the public internet consider also requiring that GET operations contain a content-type header or another specific header such as require-preflight
would be reasonable.
I wish in retrospect that we had chosen graphql-require-preflight
instead of apollo-require-preflight
for the Apollo Router/Server CSRF prevention feature so it would be more reasonable to add as a non-normative suggestion here. The DGS framework allows clients to pass either graphql-require-preflight
or apollo-require-preflight
; perhaps the spec should suggest the former? I think it wouldn't be too hard to get the Apollo implementations to support both headers too.
Other existing implementations include the graphql-yoga implementation which uses x-graphql-yoga-csrf
by default.
I see that drupal-graphql also supports apollo-require-preflight
and x-graphql-yoga-csrf
. And Pioneer supports apollo-require-preflight
.
So concretely I think my changes would be the SHOULD to MUST change above, and a non-normative suggestion that servers should consider rejecting all requests that do not contain a content-type
whose essence is a value other than text/plain
, multipart/form-data
, or application/x-www-form-urlencoded
, unless that request also contains one of a set of other header names, where that set should contain graphql-require-preflight
.
Should I do this as two separate PRs (separating the SHOULD/MUST from the rest) or just as one?
from graphql-over-http.
I'm all for adding important security notes or references when appropriate to the spec as a note.
As it particularly relates to multipart/form-data
, we should be sure not to strictly prevent it. As others have noted, bypassing CORS isn't necessarily a security risk, and changes could be made to require a preflight request and CORS validation while still using multipart/form-data
.
from graphql-over-http.
@martinbonnin and/or @glasser would you care to elaborate your concerns and/or submit non-normative notes to the GraphQL-over-HTTP spec regarding this. I'm happy to do editorial on them if you only have time for rough notes, I just want to ensure I'm capturing the important parts.
from graphql-over-http.
Thanks for following up on this!
I'll defer to @glasser for the details but my high level understanding is that some conditions make GraphQL requests more prone to CSRF issues like the ones described in this blog post:
- POSTs with a
multipart/form-data
content-type (which can be accepted by some middleware such as file uploads) could modify state bypassing CORS becausemultipart/form-data
doesn't require a preflight request. - GETs could be used for timing attacks, which are effectively the same concern as with any REST API but GraphQL make them a bit easier because of the dynamic nature of the query making it harder for the backend to reply in constant time.
For 1., might be worth requiring a content-type around here?
For 2. maybe a "security" section towards the end of the document?
from graphql-over-http.
Moving this to the GraphQL-over-HTTP WG
from graphql-over-http.
@glasser Any interest in raising a PR for this?
from graphql-over-http.
Awesome write-up; this all sounds great to me, except the SHOULD > MUST - I feel it's okay to say SHOULD
with a non-normative note stating that not implementing the behavior would open you up to potential security issues if you are dealing with browser-based clients, and thus you should X, Y and Z. If you feel strongly this isn't an appropriate way to deal with the issue then please raise it as a separate PR to enable discussion. (For clients that don't send Content-Type: application/json
or similar: command line clients are the most common, also basic HTTP clients that people write manually. Changing to MUST would force servers to become incompatible with these clients, which should have a very high bar.)
Standardizing graphql-require-preflight
sounds like a great call since it's already used fairly widely (or has similar alternatives) - I suggest raising that as a PR on its own for discussion.
from graphql-over-http.
Are there examples of popular GraphQL servers that accept POSTs with JSON bodies with no content-type header? The whole JS body-parser
-based ecosystem does not, for example. I have definitely had to type -H 'content-type: application/json'
many times to curl in my day (though with newer curl you can just use --json
instead of --body
!)
from graphql-over-http.
Are there examples of popular GraphQL servers that accept POSTs with JSON bodies with no content-type header?
The GitHub API:
curl \
-H 'Authorization: Bearer '$GITHUB_TOKEN \
-X POST \
https://api.github.com/graphql \
--data-binary '{"query":"{ organization(login:\"graphile\") { repository(name:\"crystal\") { description } } }"}'
from graphql-over-http.
Hmm, but that API basically requires an Authorization header, right?
from graphql-over-http.
Without one it seems to have a rate limit of zero currently.
from graphql-over-http.
Related Issues (20)
- Response status code as `application/json` content HOT 5
- Clarify the use of HTTP GET and POST request HOT 2
- Status codes for unauthenticated OAuth errors HOT 1
- Optional query discussion HOT 13
- GraphQL request optional parameters HOT 2
- Kitchen sink HTTP requests HOT 3
- Allow non-UTF-8 encodings HOT 2
- What is well-formed response HOT 3
- Status codes 404 and 410 HOT 1
- Clarification for `Accept: */*` HOT 8
- Should we explicitly support `Content-Type: application/graphql`? HOT 13
- Should the query property really be required? HOT 1
- Make it clear that extra keys in the request/response payloads are not allowed HOT 2
- [2023-10] Add changes promoting spec to RFC 2 status
- [2023-10] Add RFC2 status to next GraphQL Spec WG HOT 1
- Create the "Action Item" issue template
- [2024-01-25] Contact Apollo about persisted operations appendix HOT 2
- What is the rationale for handling Invalid parameters as 400? HOT 15
- Question regarding well-formedness of GQL over http responses HOT 5
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from graphql-over-http.