GraphQL requests authenticated using PAT trigger CSRF token mismatch hooks

Original Issue

Description

In https://gitlab.com/gitlab-org/govern/authentication/discussion/-/issues/124#note_2169049450 we discovered that making an API request to the GraphQL endpoint with a Personal Access Token triggers CSRF token mismatch and a subsequent call to handle_unverified_request.

This method has a few side effects usually, but currently doesn't have any because request forgery protection hooks are being triggered before we authenticate a user with PAT, otherwise this would sign a user out.

We should probably disable CSRF protection if user authenticates with a PAT (and user session is not present).

It might be important to fix this because it is difficult to predict how and when this might evolve into a real problem in production. We might add more features to the request forgery protection middleware in the future, and then this can cause a production incident.

We currently trigger around 300 CSRF token mismatch events per second on GraphQL endpoint:

user_csrf_graphql_controller_2024-10-21_10-39

Summary

In this comment we discovered that making an API request to the GraphQL endpoint with a Personal Access Token triggers CSRF token mismatch and a subsequent call to handle_unverified_request.

This method has a few side effects usually, but currently doesn't have any because request forgery protection hooks are being triggered before we authenticate a user with PAT, otherwise this would sign a user out.

We should probably disable CSRF protection if user authenticates with a PAT (and user session is not present).

It might be important to fix this because it is difficult to predict how and when this might evolve into a real problem in production. We might add more features to the request forgery protection middleware in the future, and then this can cause a production incident.

We currently trigger around 300 CSRF token mismatch events per second on GraphQL endpoint:

user_csrf_graphql_controller_2024-10-21_10-39

Steps to Reproduce

  1. Generate a Personal Access Token (PAT) for authentication
  2. Make a request to the GraphQL API endpoint using the PAT for authentication
  3. Observe the CSRF token mismatch and handle_unverified_request response

What is the Current Bug Behaviour?

  • A CSRF token mismatch error is triggered
  • The handle_unverified_request method is called, which could potentially sign out the user in the future if additional hooks are added
  • Approximately 300 CSRF mismatch events occur per second on the GraphQL endpoint

What is the Expected Correct Behaviour?

  • When a user authenticates with a PAT (and without a user session), CSRF protection should be disabled, allowing the request to proceed without triggering handle_unverified_request

Possible Fixes

See this comment

We can implement this by overriding the #verified_request? method of the controller.

Edited Nov 04, 2024 by Hakeem Abdul-Razak
Assignee Loading
Time tracking Loading