Webhook secret signature question

Must-share information (formatted with Markdown):

  • which versions are you using (SonarQube, Scanner, Plugin, and any relevant extension)
    v10 (the latest)
  • how is SonarQube deployed: zip, Docker, Helm
    (Docker via docker compose yaml)
  • what are you trying to achieve
    (customized code review automation)
  • what have you tried so far to achieve this
    (spin up self hosted server, everything works based on documentation reading except for one thing)
    Do not share screenshots of logs – share the text itself (bonus points for being well-formatted)!

Hi SonarQube Community,

I’m using webhook feature on the system level to send my own server a notification when a analysis is completed.
I created a webhook with a secret in sonarqube system configuration page.
and then I’m using nodejs server to receive the webhook incoming call from sonarqube.
I’m at the verification step to ensure the incoming call is from Sonarqube for security compliance.
according to the sonarqube’s documentation it’s based on Hmac sha256, so I did the below nodejs code, however, the signature doesn’t match.

I have tried to print the raw req.body data with JSON.stringify(req.body), it seems matching with the request payload that sonarqube sent, although I’m not certain what’s the internal mechanism on creating the signature.

Any ideas how I can get that matched for an enhanced security ?

            const hash = crypto.createHmac('sha256', process.env.sonarQubeWebhookSecret).update(JSON.stringify(req.body)).digest('hex');
            // get the hash from the request header
            const webhookSignature = req.headers['x-sonar-webhook-hmac-sha256'];
            // and now compare to see if they match.
            if (webhookSignature === hash) {
                next();
            } else {
                const error = new Error(`Error: Invalid signature at ensureValidSonarQubeTraffic. ExpectedHash: ${hash}. GotHash ${webhookSignature}`);
                error.status = 403;
                next(error);
            }

Hello,

the snippet provided by the documentation is in java and looks like this:

private static boolean isValidSignature(YourHttpRequest request) {
  String receivedSignature = request.getHeader("X-Sonar-Webhook-HMAC-SHA256");
  // See Apache commons-codec
  String expectedSignature = new HmacUtils(HmacAlgorithms.HMAC_SHA_256, "your_secret").hmacHex(request.getBody())
  return Objects.equals(expectedSignature, receivedSignature);  
}

In this example, we are using the lib from apache commons-codec HmacUtils class.
There are two noteworthy elements here that could explain the difference with your code:

  • All the Strings (passcode and content) that are used to create the digest are read with UTF-8
  • the body of the response itself is used for calculating the hash. Any change in formatting between the response and JSON.stringify(req.body) would affect the result.

I hope this will help you, in any case don’t hesitate to come back!

1 Like

I see what you are saying, I will do more research.
Thanks, Steve.

1 Like