@graphql-yoga/plugin-csrf-prevention
Version: 
CSRF prevention plugin for GraphQL Yoga that requires the clients to have a specific header set.
47 lines (46 loc) • 1.89 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.useCSRFPrevention = useCSRFPrevention;
const graphql_yoga_1 = require("graphql-yoga");
const NON_PREFLIGHTED_CONTENT_TYPES = [
    'application/x-www-form-urlencoded',
    'multipart/form-data',
    'text/plain',
];
/**
 * If you have CORS enabled, almost all requests coming from the browser will have a
 * preflight request - however, some requests are deemed "simple" and don't make a preflight.
 *
 * One example of such a request is a good ol' GET request without any headers, this request can
 * be marked as "simple" and have preflight CORS checks skipped therefore skipping the CORS check.
 *
 * This attack can be mitigated by saying: "all GET requests must have a custom header set". This
 * would force all clients to manipulate the headers of GET requests, marking them as "_not-_simple"
 * and therefore always executing a preflight request.
 */
function useCSRFPrevention(options = {}) {
    const { requestHeaders = ['x-graphql-yoga-csrf'] } = options;
    return {
        onRequestParse({ request }) {
            if (wasTheRequestAlreadyPreflightChecked(request.headers?.get('content-type'))) {
                return;
            }
            if (requestHeaders.some(headerName => request.headers.has(headerName))) {
                return;
            }
            throw (0, graphql_yoga_1.createGraphQLError)('Required CSRF header(s) not present', {
                extensions: {
                    http: {
                        status: 403,
                    },
                },
            });
        },
    };
}
const wasTheRequestAlreadyPreflightChecked = (contentType) => {
    if (!contentType) {
        return false;
    }
    return !NON_PREFLIGHTED_CONTENT_TYPES.some(nonPreflightContentType => contentType.toLowerCase().startsWith(nonPreflightContentType));
};