Secure your webhooks
Once you've created webhooks from the dashboard and are ready to integrate them into your system, it's crucial to prioritize security to prevent vulnerabilities in your application. Here are the steps to enhance the security of your webhooks:
1. Whitelist our IP address
The first line of defense is to whitelist our IP addresses to ensure that only authorized calls from Bridge API reach your webhook endpoints. We consistently call your callback URL from the following IP addresses:
63.32.31.5
52.215.247.62
34.249.92.209
Use the X-Forwarded-For Header
To accurately identify the source IP, make use of the X-Forwarded-For header included in the HTTP request.
2. Use the Provided Secret to Check Signatures
Webhooks Signature
Every time a webhook is created, an automatically generated secret is assigned to it. This secret plays a critical role in securing your webhook communication. It is used to sign every event sent to your webhook endpoint. Keep in mind:
- The secret is only displayed once after the webhook's creation or after updating the current secret.
- You can update your secret from the dashboard by editing an existing webhook. The previous secret remains valid for 24 hours after the update to allow you time to replace it in your backend.
A webhook cannot have more than 2 secrets at the same time
A webhook cannot have more than two active secret signatures simultaneously. If you update your secret twice consecutively without updating your code, the first secret becomes invalid.
Verifying Webhook Signatures
To ensure the authenticity of events received at your webhook endpoints, verify their signatures. Each event includes a BridgeApi-Signature header that contains one or more signatures, each prefixed by a scheme. The only valid live signature scheme is v1. To prevent potential downgrade attacks, disregard any schemes other than v1.
Example:
BridgeApi-Signature:
v1=E5637CDB3A54ECA10DDA9D515E588B6BECDABA414537FFC488B63474081B90DF,v1=82918263E23D1A67DD5B47E190AB62EAF9DDBB9920F48569120ED67E95286CF4
These signatures are generated using an HMAC with SHA-256 hash function. The endpoint's signing secret serves as the key, and the received event, in string format, acts as the message.
It is possible to have multiple signatures with the same scheme-secret pair
This can happen when you update a webhook's secret from the Dashboard, because the previous secret is still active for up to 24 hours. During this time, your callback URL has multiple active secrets and we generated one signature for each secret.
Step 1: Extract Signatures from the Header
Split the header using the , character as the separator to obtain a list of elements. Then, split each element using the =
character as the separator to isolate a prefix and value pair. The value corresponding to the prefix v1 represents the signature(s), while other elements can be discarded.
Step 2: Determine the Expected Signature
Compute an HMAC with the SHA-256 hash function. Use the endpoint's signing secret as the key and the received event (in string format) as the message.
Step 3: Compare the Signatures
Compare the signature(s) in the header to the expected signature(s).
3. Signature verification: examples
In the following examples, SECRET
represents your signature secret, and PAYLOAD
is the entire body sent by the webhook. When you test these examples with the provided values:
SECRET = “644b2ac3-0797-4ec6-9537-cb5c0af9caf9”
PAYLOAD = "{\"content\":{\"item_id\":1234567890,\"status\":0,\"user_uuid\":\"9a95b38f-f98b-417a-988b-9d0d584893e7\"},\"timestamp\":1611681789,\"type\":\"TEST_EVENT\"}"
or depending on the method:
PAYLOAD = "{"content":{"item_id":1234567890,"status":0,"user_uuid":"9a95b38f-f98b-417a-988b-9d0d584893e7"},"timestamp":1611681789,"type":"TEST_EVENT"}"
You should obtain the following signature: FAA8ECAC21DA6405D789C76EDB4003756398E7169DACC3FA70CF5919A81374A8
Here are example code snippets to generate this result in different programming languages:
var crypto = require('crypto');
var hash = crypto.createHmac('SHA256', SECRET).update(PAYLOAD).digest('hex');
console.log(hash.toUpperCase());
Mac hasher = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(SECRET.getBytes(), "HmacSHA256");
hasher.init(secretKey);
byte[] signedContent = hasher.doFinal(PAYLOAD.getBytes());
System.out.println(DatatypeConverter.printHexBinary(signedContent));
import hmac
import hashlib
signature = hmac.new(bytes(API_SECRET , 'utf-8'), msg = bytes(message, 'utf-8'), digestmod = hashlib.sha256).hexdigest().upper()
print(signature)
For security reasons, when we call your webhook URL, ensure that your response body remains under 10 KB in size to prevent potential issues.
Updated about 1 year ago