Skip to content

Supporting POSTs with multipart/form-data is dangerous without CSRF protection  #270

@glasser

Description

@glasser

We recently discovered that supporting multipart/form-data POSTs in GraphQL servers makes it very likely that your server will be vulnerable to executing GraphQL mutations in CSRF attacks unless otherwise prevented.

(I'm a maintainer of Apollo Server. We today announced an advisory against an old version of our software that supported these requests by default, and opened a PR against the GraphQL multipart spec warning about this class of issues. Some of our users also use Absinthe which brought your implementation to my attention.)

This issue generally happens if:

  • Your CORS policy implementation functions just by setting access-control-allow- headers rather than by actually rejecting operations with disallowed origins. (Note that this is probably reasonable because it's easy for JS to send cross-origin GET requests without an origin header by inserting IMG tags or similar; that said, cross-origin POST requests in modern browsers should generally have an origin header.) While I'm not an expert, it does look like this is how the CORS Plug works.
  • Your server uses cookies for authentication or depends on some other property of the browser such as its IP address or access to private networks via VPN.

At the very least, now that this issue is known, I'd highly encourage you to highlight in docs that adding :multipart to your server is something you should only do if you're definitely using the upload feature (vs just by default) and only if you understand and are mitigating CSRF.

For what it's worth, Plug.CSRFProtection seems like overkill for this case. That uses a stateful CSRF token, which typically is what you need if you require normal form submission without JS to be able to send successful requests. Since GraphQL users are typically using JS, it's enough to just require some header like GraphQL-Require-Preflight to have a non-empty value, which is enough to make browsers preflight.

(We recently wrote some docs about CORS and CSRF which we think are helpful if it's not something you are deeply familiar with.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions