Bitbucket webhook HTTP requests can have an X-Hub-Signature header field that contains the HMAC of the request body. The key of the HMAC is a secret that must be configured beforehand. The Bitbucket Branch Source plugin for Jenkins could be enhanced to let the administrator input this secret and to validate the incoming HTTP requests.
The X-Hub-Signature header field is documented in:
It looks like these are compatible with each other, so the HMAC validation would only need to be implemented once.
I suppose the HMAC must be computed from the byte stream, preferably before decoding to a Java string, and definitely before parsing JSON. In the Bitbucket Branch Source plugin, the BitbucketSCMSourcePushHookReceiver.doNotify(StaplerRequest2) method decodes from UTF-8 to a string:
String body = IOUtils.toString(req.getInputStream(), StandardCharsets.UTF_8);
and passes this string to an implementation of HookProcessor.process(HookEventType, String, BitbucketType, String), which then parses JSON. The plugin does not know the project and repository before it parses this JSON; and it cannot compute the HMAC before it has located the HMAC key. Ways to solve this:
- Change the HookProcessor interface so it takes the request body as an array of bytes rather than a string.
- Con: This might make debugging less convenient.
- Encode the Java string back to UTF-8 and compute the HMAC from that.
- Con: The conversions back and forth feel silly.
- Make the HMAC key a global setting in Jenkins and require that all authenticated Bitbucket webhooks use the same HMAC key.
- Con: The Jenkins administrators might have to disclose the HMAC key to multiple teams who set up webhooks in their Bitbucket repositories, weakening security.
- Add a key identifier as a query parameter in the webhook URL. Use that to locate the correct HMAC key and validate the request. Pass the key identifier to HookProcessor too, and verify that this key is authorized to sign webhook requests to the specific repository.
- Con: Would need a mapping from key identifiers to HMAC keys. If the key identifier is just the credential ID in Jenkins, it might be safest to define a new credential type for this purpose, so as to prevent attackers from using fake Bitbucket webhook requests to probe unrelated credential IDs in Jenkins.
- Administrators would have to reconfigure the webhook URLs in Bitbucket when deploying this change. This would not cause much extra work because the administrators would have to configure webhook secrets in Bitbucket anyway.
The first of these options looks best.
Bitbucket webhook HTTP requests can have an X-Hub-Signature header field that contains the HMAC of the request body. The key of the HMAC is a secret that must be configured beforehand. The Bitbucket Branch Source plugin for Jenkins could be enhanced to let the administrator input this secret and to validate the incoming HTTP requests.
The X-Hub-Signature header field is documented in:
It looks like these are compatible with each other, so the HMAC validation would only need to be implemented once.
I suppose the HMAC must be computed from the byte stream, preferably before decoding to a Java string, and definitely before parsing JSON. In the Bitbucket Branch Source plugin, the BitbucketSCMSourcePushHookReceiver.doNotify(StaplerRequest2) method decodes from UTF-8 to a string:
String body = IOUtils.toString(req.getInputStream(), StandardCharsets.UTF_8);
and passes this string to an implementation of HookProcessor.process(HookEventType, String, BitbucketType, String), which then parses JSON. The plugin does not know the project and repository before it parses this JSON; and it cannot compute the HMAC before it has located the HMAC key. Ways to solve this:
The first of these options looks best.