最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

php - How to Validate Bitbucket Webhook Signature Using Secret Key? - Stack Overflow

programmeradmin4浏览0评论

I'm trying to set up an automatic deployment when a pull request is merged into the main branch using Bitbucket webhooks.

However, I'm facing an issue with validating the webhook signature using the secret key.

What I Have

My secret key: q3bn5JCdR1yqK46V. (Already changed before posting this)

The webhook triggers correctly and sends the following headers:

X-Hub-Signature: sha256=51ff4d1fe17b05bc6c649abf4bb09e0f3d8d90d45faa43abcf66822cb658ae57
X-Hub-Signature-256: sha256=51ff4d1fe17b05bc6c649abf4bb09e0f3d8d90d45faa43abcf66822cb658ae57

What I'm Doing

I assumed the X-Hub-Signature-256 is the HMAC-SHA256 hash of the payload using my secret key, so I'm trying to generate the same hash with:

$hash = 'sha256=' . hash_hmac('sha256', $payload, $secret);

However, the hash I generate does not match the one provided in the headers.

How can I validate the Bitbucket webhook secret key using the content sent in the request?

I'm trying to set up an automatic deployment when a pull request is merged into the main branch using Bitbucket webhooks.

However, I'm facing an issue with validating the webhook signature using the secret key.

What I Have

My secret key: q3bn5JCdR1yqK46V. (Already changed before posting this)

The webhook triggers correctly and sends the following headers:

X-Hub-Signature: sha256=51ff4d1fe17b05bc6c649abf4bb09e0f3d8d90d45faa43abcf66822cb658ae57
X-Hub-Signature-256: sha256=51ff4d1fe17b05bc6c649abf4bb09e0f3d8d90d45faa43abcf66822cb658ae57

What I'm Doing

I assumed the X-Hub-Signature-256 is the HMAC-SHA256 hash of the payload using my secret key, so I'm trying to generate the same hash with:

$hash = 'sha256=' . hash_hmac('sha256', $payload, $secret);

However, the hash I generate does not match the one provided in the headers.

How can I validate the Bitbucket webhook secret key using the content sent in the request?

Share Improve this question edited Feb 7 at 15:45 hakre 198k55 gold badges446 silver badges854 bronze badges Recognized by PHP Collective asked Feb 7 at 15:27 Gustavo SoaresGustavo Soares 355 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 3

This is what I am using for Github actions.

Note, to compare the hashes via hash_equals function!

Also note, the header keys are underscored in the $_SERVER globals array. The dashes are transformed by PHP.

In addition to the elements listed below, PHP will create additional elements with values from request headers. These entries will be named HTTP_ followed by the header name, capitalized and with underscores instead of hyphens. For example, the Accept-Language header would be available as $_SERVER['HTTP_ACCEPT_LANGUAGE'].

$body = file_get_contents(filename: 'php://input');
$signature = $_SERVER['HTTP_X_HUB_SIGNATURE_256'] ?? '';

$expected = 'sha256=' . hash_hmac(algo: 'sha256', data: $body, key: $secret);
if (hash_equals($signature, $expected)) {
    return true;
}

This is an addition to Markus Zellers' answer, as it is relevant for Atlassian Bitbucket Webhooks and may be relevant for the individual use-case.

Marcus shows how to use hash_hmac() for the known X-Hub-Signature header value for the case of one signature only:

enum BitbucketSignature
{
    case sha256;
}

This is fine right now, but the algorithm may change. (ref)

enum BitbucketSignature
{
    case sha256;
    case sha384;
    case sha512;
}

PHP would handle it regardlessly, if supported via hash_hmac_algos():

in_array($algo?->name, hash_hmac_algos())

Originally, the enum was only descriptive; it would also allow putting the moving parts into it for convenience:

enum BitbucketSignature
{
    case sha256;
    case sha384;
    case sha512;
    
    public static function authContents(...) : ?string{...}
}

...

$contents = BitbucketSignature::authContents(
    signature: @$_SERVER['HTTP_X_HUB_SIGNATURE'],
    payload: file_get_contents(filename: 'php://input'),
    secret: $secret,    
);

The $contents is authenticated, null otherwise.

Try: https://phpstan.org/r/5e1f4c87-78e5-42aa-9976-a650e3663fca

Demo: https://3v4l.org/kbSg5

Options:

  • Given null, respond with HTTP 2xx quickly to confirm the delivery (not the authenticity).

  • Given authentic, you may want to check if the content matches your expectation of the payloads Content-Type.

发布评论

评论列表(0)

  1. 暂无评论