Securing webhooks

Ensure your server is only receiving the expected Sirius requests for security reasons.

Once your server is configured to receive payloads, it'll listen for any payload sent to the endpoint you configured. For security reasons, you probably want to limit requests to those coming from Sirius. Sirius allow you to set up a secret token and validate the information.

Setting your secret token

You'll need to set up your secret token in two places: Sirius and your server.

To set your token on Sirius:

  1. Navigate to the Apps admin page and select the application to secure.

  2. Fillout the "Secret" field. It is your responsability to register a secured secret. We suggest to use a random string with high entropy (e.g. in Node.js by taking the output of crypto.randomBytes(20).toString("hex") at the terminal).

  3. Save your app configuration.

Next, set up an environment variable on your server that stores this token. Typically, this is as simple as running:

$ export SECRET_TOKEN=your_token

Never hardcode the token into your app!

Validating payloads from Sirius

When your secret token is set, Sirius uses it to create a hash signature with each payload. This hash signature is included with the headers of each request as X-Sirius-Signature-256.

The intention is to calculate a hash using your SECRET_TOKEN, and ensure that the result matches the hash from Sirius. Sirius uses an HMAC hex digest to compute the hash.

const crypto = require("crypto");
const compare = require("secure-compare");
const verifySignature = (req) => {
const signature = req.get("X-Sirius-Signature-256");
const payload = req.body;
const hash = crypto
.createHmac("sha256", process.env.SECRET_TOKEN)
.update(payload)
.digest("base64");
const match = compare(`sha256=${hash}`, signature);
if (!match) {
throw new Error("Signatures didn't match!");
}
};

Note: Webhook payloads can contain unicode characters. If your language and server implementation specifies a character encoding, ensure that you handle the payload as UTF-8.

Your language and server implementations may differ from this example code. However, there are a number of very important things to point out:

  • No matter which implementation you use, the hash signature starts with sha256=, using the key of your secret token and your payload body.

  • Using a plain == operator is not advised. A package like secure-compare performs a "constant time" string comparison, which helps mitigate certain timing attacks against regular equality operators.

Edit this page on GitHub