GraphQL Non-JSON Mutations over GET: Potential CSRF Vulnerability
Description
This GraphQL implementation accepts mutation operations via HTTP GET requests with non-JSON content types (such as query parameters or form data). Unlike JSON-based POST requests which browsers restrict from cross-origin forms, GET-based mutations can be triggered through simple HTML elements like images or links, making them vulnerable to Cross-Site Request Forgery (CSRF) attacks. GraphQL mutations are operations that modify server-side data (create, update, or delete), and should be protected against unauthorized cross-site execution.
Remediation
Implement the following security controls to prevent CSRF attacks on GraphQL mutations:
1. Restrict mutations to POST requests only: Configure your GraphQL server to reject mutation operations sent via GET requests. Most GraphQL server libraries provide configuration options for this.
Example for Express-GraphQL:
app.use('/graphql', graphqlHTTP({
schema: schema,
graphiql: false,
customExecuteFn: (args) => {
if (args.operationName && isMutation(args.document)) {
if (request.method !== 'POST') {
throw new Error('Mutations must use POST requests');
}
}
return execute(args);
}
}));2. Enforce JSON content type: Require the Content-Type header to be 'application/json' for all mutation requests.
3. Implement CSRF tokens: Add anti-CSRF tokens to all mutation requests and validate them server-side.
4. Use SameSite cookies: Set the SameSite attribute to 'Strict' or 'Lax' on authentication cookies to prevent them from being sent with cross-site requests.
5. Verify request origin: Validate the Origin and Referer headers to ensure requests originate from trusted domains.