Skip to content

Draft: POC for HMAC webhook signing

  • Please check this box if this contribution uses AI-generated content (including content generated by GitLab Duo features) as outlined in the GitLab DCO & CLA

What does this MR do and why?

Relates to #19367.

This MR outlines an implementation for sending an HMAC digest with a webhook that will be more secure than our current secret token implementation. The implementation here closely follows Slack's implementation (https://api.slack.com/authentication/verifying-requests-from-slack) as this was a recommended model to emulate.

The main points of the MR are:

(Note: updated and detailed technical walkthrough in !163102 (comment 2090363939))

  • added signing_token to the web_hooks table
  • added post migrations to fill in existing signing_tokens with md5 hashes
  • added a signing token field to the webhook form
  • added a RequestSigner class to encapsulate the HMAC digest and header creation logic
  • implements RequestSigner in WebHookService to send signed headers

As a companion to this feature, I used Anthropic Sonnet 3.5 to generate a webhook receiver that will simulate a client verifying the signed webhook: https://gitlab.com/van.m.anderson/gitlab-webhook-receiver. This project publishes a docker image that can run with minimal configuration.

Testing

(Note: newer front end flows are documented in !163102 (comment 2085730844))

HMAC-signing-token-HD-demo

  1. In order to test local webhooks, you will have to have allow_local_requests_from_web_hooks_and_services set to true in the Application Settings. This can be accomplished in the rails console:
gdk rails c
s = ApplicationSetting.first
s.allow_local_requests_from_web_hooks_and_services = true
s.save!
  1. Create a new webhook and set the url to http://127.0.0.1:4567/webhook.

  2. Reveal the signing token field by clicking the eye icon and copy the hash.

  3. In a terminal window, set SIGNING_TOKEN to this copied value:

export SIGNING_TOKEN=<copied_value_here>
  1. Run the webhook receiver docker image with this command:
docker run -p 4567:4567 \
  -e SIGNING_TOKEN=$SIGNING_TOKEN \
  -e PORT=4567 \
  registry.gitlab.com/van.m.anderson/gitlab-webhook-receiver:v0.1.5
  1. Trigger a test webhook in the gitlab instance.

  2. Go back to the terminal running the webhook receiver and observe the result - the received webhook should be verified.

  3. Go back to the webhook edit form for the webhook that was previously triggered and change the Signing Token by clicking the cycle icon.

  4. Save the webhook.

  5. Trigger the same test webhook in the gitlab instance.

  6. Go back to the terminal running the webhook receiver and observe the result - the received webhook should fail verification due to the signing token changing.

Todo actions and implementation discussion.

  • The current secret token is handled very carefully. We don't render the value in the form after a user saves it for the first time, only allowing a user to replace it with a new value. The signing token is an equal security liability. In this POC implementation, we render it as a show/hide password field where ever the WebHook form is rendered (just as the Slack implementation does). Does this need to be more secure?

  • Changing the signing token could potentially break integrations, and this implementation only allows users to regenerate a new token as a random value. So if a user changes the token, there is no going back to the original value like you can in the Secret Token field. This has security benefits, but might also have user consequences. Should we throw a warning flash message when the user clicks the regenerate button to warn them about this? Or will users implicitly understand the consequences?

  • Would it be worth adding a "copy" button to the Signing Token field along with the show/hide and regenerate?

  • The documentation for this feature will likely need to be substantial - when the feature details are confirmed, should I make a first pass on the documentation and tag in a technical writer when there is something to review? Or is there another process for this?

Edited by Van Anderson

Merge request reports

Loading