Skip to content

Create new spam protection concern for mutations

Alex Kalderimis requested to merge ajk-snippet-raise-on-spam into master

What are we doing right now

Create new spam protection concern for mutations

Currently we are raising spam errors as part of the mutation response, so for example:

{
  "data": {
    "updateSnippet": {
      "errors": [
        "Your snippet has been recognized as spam. Please, change the content or solve the CAPTCHA to proceed."
      ],
      "snippet": {
        "webUrl": "http://gitlab.leipert:3000/-/snippets/23",
        "__typename": "Snippet"
      },
      "needsCaptchaResponse": true,
      "captchaSiteKey": "6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI",
      "spamLogId": 67,
      "__typename": "UpdateSnippetPayload"
    }
  }
}

This has a few downsides:

  1. Adding CAPTCHA fields and arguments to our GraphQL Schema. This means that we need to change mutations to support CAPTCHAs.
  2. The CAPTCHA fields are also part of a specific path and generally handling those SPAM Errors become harder.
  3. Sending the CAPTCHA Result means we need to mutate the variables of the query.
sequenceDiagram
    participant U as User
    participant V as Vue Application
    participant A as Apollo
    participant G as GitLab API
    U->>V: Save snippet
    V->>A: Request
    A->>G: Request
    G-->>A: Response with Error in mutation response
    A-->>V: Response with Error in mutation response
    V->>U: Please solve CAPTCHA
    U->>V: CAPTCHA Solution
    V->>A: Request with solved CAPTCHA Data
    A->>G: Request with solved CAPTCHA Data
    G-->>A: Response with Success
    A-->>V: Response with Success

This MR proposes to change the implementation to raise a top-level error instead; references: graphql-ruby, graphql spec).

When sending the request again after solving the CAPTCHA, we send the CAPTCHA solution via the HTTP header X-GitLab-Captcha-Response.

Semantically the most apt comparison might be authorization, so raising a top-level error makes sense. If the backend registers something as SPAM

  1. We fail un-recoverably (SpamDisallowedError), which would be like a 403 Forbidden
  2. We fail with CAPTCHA Data (NeedsCaptchaResponseError), which would be like a 401 Unauthorized, requiring authorization

The same response from above might be looking something like this now:

{
  "errors": [
    {
      "message": "Request has been denied: Solve captcha challenge and retry",
      "locations": [ { "line": 6, "column": 7 } ],
      "path": [ "updateSnippet" ]
      "extensions": {
        "needsCaptchaResponse": true,
        "captchaSiteKey": "6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI",
        "spamLogId": 67
      }
    }
  ],
  "data": {
    "updateSnippet": {
      "snippet": null,
      "__typename": "UpdateSnippetPayload"
    }
  }
}

Handling errors this way allows us to:

  1. Parse the errors independently from contents of the query response
  2. Set the HTTP headers independently from the contents of the query
sequenceDiagram
    participant U as User
    participant V as Vue Application
    participant A as Apollo
    participant G as GitLab API
    U->>V: Save snippet
    V->>A: Request
    A->>G: Request
    G--xA: Response with top-level Error
    A->>U: Please solve Captcha
    U->>A: Captcha Solution
    A->>G: Request with solved Captcha Data in headers
    G-->>A: Response with Success
    A-->>V: Response with Success

Screenshots (strongly suggested)

What Before After
General workflow snippets-before snippets-after
SPAM detected without CAPTCHA configured Screenshot_2021-03-25_at_22.07.37 Screenshot_2021-03-25_at_21.58.19

Does this MR meet the acceptance criteria?

Conformity

Availability and Testing

NOTE: See the CAPTCHA Improvements epic Testing Notes section for details on how to set up your local dev environment to test CAPTCHAs

Security

If this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in the security review guidelines:

  • Label as security and @ mention @gitlab-com/gl-security/appsec
  • The MR includes necessary changes to maintain consistency between UI, API, email, or other methods
  • Security reports checked/validated by a reviewer from the AppSec team

Related

Edited by Lukas 'ai-pi' Eipert

Merge request reports