0

My JavaScript code is making the following POST API call to my endpoint:

const payload = {
   course: args,
   recipient: roomId
};
const signature = this.calculateSignature(JSON.stringify(payload), secret);

const response = await fetch(`https://crmpicco.co.uk/app/api/dsf7s9d8797987897987`, {
   method: 'POST',
   headers: {
      'Content-Type': 'application/json',
      'X-EchoBot-Signature-256': signature 
   },
   body: JSON.stringify(payload)
});

calculateSignature(payload, secret) {
   return "sha256=" + crypto
   .createHmac('sha256', secret)
   .update(payload)
   .digest('hex');
}

in my Symfony 5.4 PHP app I have the following code:

$echoSecret = "0IQgWRFC1872i6AQc3mDo3Dc48UfWATPCoRX";

$encodedPayload = json_encode(json_decode($request->getContent()));
$calculatedSecret = hash_hmac('sha256', $encodedPayload, $echoSecret);
if ($headers['x-echobot-signature-256'][0] == "sha256=" . $calculatedSecret) {
    $this->getLogger()->info('The signature is valid, proceed...', [
        'calculatedSecret' => $calculatedSecret,
        'headerSecret' => $headers['x-echobot-signature-256'][0]
    ]);
} else {
    $this->getLogger()->info('The signature is invalid :(', [
        'calculatedSecret' => $calculatedSecret,
        'headerSecret' => $headers['x-echobot-signature-256'][0]
    ]);
}

Everytime I call the endpoint the authentication fails and falls into the The signature is invalid :( else block.

The request looks like this:

"request":{"stdClass":{"course":["topaid33"],"recipient":"!LjZCWlshucBDhBobTT:crm.com"}},"payload":"{"course":["topaid33"],"recipient":"!LjZCWlshucBDhBobTT:crm.com"}","headers":{"accept-encoding":["gzip, deflate, br"],"content-type":["application/json"],"user-agent":["Amazon CloudFront"],"x-amz-cf-id":["ndCQJ9lvWATP_vSerFFFFaqHBhYqOn_wdSLF2vWBShXCBA=="],"x-cloudfront-key":["RFC1872"],"x-matrixbot-signature-256":["sha256=3577f59ea6f1dd44af8af2e9240093387897897987987a029ccf818ae92ee2cdb99"],"x-forwarded-port":["443"],"x-forwarded-proto":["https"],"content-length":["78"],"via":["1.1 ip-10-82-2-81 (Varnish/7.2)"],"host":["s.crmpicco.co.uk"],"x-varnish":["3735722"],"x-php-ob-level":["1"]

Where am I taking a mis-step here?

3
  • Are the two input data for the HMAC and the HMAC generated from it identical on both sides? Commented Nov 6, 2023 at 7:26
  • @Topaco They should be, yes. Would ordering have any effect here? Commented Nov 6, 2023 at 7:50
  • The HMAC works with bytes. It only returns the same value if the byte sequence is the same (value, number and order). For a JSON string, this means that the elements must also match regarding value, number and order. What's more, even the formatting (whitespaces etc.) and of course the encoding (e.g. UTF8) must be identical. It is best to compare the hex encoding of the (e.g. UTF8) encoded JSON string, which provides a 1:1 mapping of the bytes that are processed by the HMAC. This hex encoding must be the same. Commented Nov 6, 2023 at 8:57

1 Answer 1

0

compare hashes using the hash_equals function


$signature = $request->header('x-echobot-signature-256');

$computedSignature = hash_hmac('sha256', (string) $request->getContent(), $echoSecret);

hash_equals($signature, $computedSignature)
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.