Data security is key to maintaining the integrity and confidentiality of Personal Identifiable Information (PII) within organization. As more systems rely their operations on real-time data, the risk of tampering and unauthorized goes higher.
This is where webhooks come in – an efficient way to send automated notifications when specific events occur.
However, just transmitting data via webhooks isn’t enough to secure it.
To protect sensitive data, verifying the authenticity of data sent through webhooks is essential.
At Bindbee, we use HMAC (Hash-based Message Authentication Code) to secure our webhook payloads, ensuring that the data remains intact during transmission.
This article walks you through everything you need to know about HMAC, and how you can implement it to secure your Webhooks.
Let’s dive right in!
Why Data Security Matters for Webhooks
Without the right measures in place, webhooks are at risk of the following:
- Data Tampering: Unauthorized modifications to the data in transit.
- Replay Attacks: Malicious actors can resend a legitimate webhook multiple times to trigger unwanted actions.
- Forged Requests: Attackers may send forged webhook requests to your system, pretending to be a trusted source.
HMAC offers a straightforward and reliable way to ensure that your webhooks are both authentic and unaltered.
What is HMAC?
HMAC is a cryptographic technique that combines a hash function (e.g., SHA-256) with a secret key to authenticate and verify the integrity of messages.
In simpler terms, HMAC allows you to ensure that the data you’re receiving through webhooks hasn’t been tampered with and comes from a trusted source.
It works by generating a unique signature (or hash) for each message, using a secret key shared between the sender and receiver.
Why Use HMAC Instead of Simple Hashing?
While hashing algorithms like SHA-256 can create a fingerprint of the message, they don’t offer enough security when used alone for authentication.
A simple hash can be intercepted, and attackers can generate their own hashes using the same payload, sending unauthorized requests.
HMAC, on the other hand, incorporates a secret key known only to the sender and receiver.
This key makes it nearly impossible for an attacker to replicate the signature without access to the secret. Even if they can see the webhook payload and its corresponding hash, they won’t be able to forge requests without the shared key.
HMAC in Action: A Breakdown
Let’s break down how HMAC works step-by-step:
- Hash Function: HMAC uses a cryptographic hash function (e.g., SHA-256) to generate the message hash.
- Secret Key: A secret key is combined with the hash to produce a unique signature.
- Message Integrity: When the recipient receives the message, they recreate the hash using the same secret key and compare it to the original signature. If both match, the message is considered valid and untampered.
This ensures that any alteration to the message or signature during transit will be immediately detected by the receiver, providing a strong layer of protection.
How to Implement HMAC for Your Webhooks: An HR-Tech Example
Imagine you work for a HR-Tech company, let’s call them WorkWise.
WorkWise is used by large enterprise companies to manage employee records, process payroll, and coordinate benefits. Your enterprise customers - typically large HR departments—rely on the platform’s webhooks to receive real-time updates when key employee events occur, such as promotions, status changes, or benefits enrolment.
Now, If an attacker were to intercept or tamper with these payloads, it could lead to disastrous consequences for both the HR team and the employees whose data is compromised.
HMAC provides a way to secure these webhooks by verifying the data source is authentic and unaltered. Here’s how WorkWise can implement HMAC to secure webhook payloads:
1. Generate a Secret Key
The first step is to generate a unique secret key for each enterprise customer. This secret key acts like a password shared only between WorkWise and the customer’s HR system.
For example, when a new enterprise customer like say, TechCorp onboards to WorkWise, the platform generates a secret key such as sK3j94vJg6dPqTx3c1
. This key will be used every time a webhook payload is sent from WorkWise to TechCorp’s internal HR system.
2. Hash the Payload
Next, WorkWise needs to generate a signature for every webhook payload it sends. To do this, the platform takes the payload (the data being sent) and combines it with the customer’s secret key to create a hash.
Let’s say an employee at TechCorp, let’s call him John Doe, has just been promoted. WorkWise sends a webhook to TechCorp’s HR system containing this information:
{
"event": "employee.promoted",
"employee_id": "12345",
"employee_name": "John Doe",
"new_position": "Senior Developer"
}
WorkWise takes this payload and, using a hashing algorithm like SHA-256, combines it with TechCorp’s secret key (sK3j94vJg6dPqTx3c1)
. The result is a hashed signature, which might look something like:
92f7d716849c1f4898ad076ce057492233cde8a7a45a790d89f0f963eb78c88c
This signature uniquely represents the contents of the payload and can be verified by TechCorp's system to ensure the integrity of the data.
Here’s how the sample code post generation would look like:
import hmac
import base64
import hashlib
import json
#The secret key that is used to generate the signature
secret_key = "sK3j94vJg6dPqTx3c1"
# the request body that is to be sent in the webhooks payload
request_body = {
"event": "employee.promoted",
"employee_id": "12345",
"employee_name": "John Doe",
"new_position": "Senior Developer"
}
#Converting the request body to the json string
request_body = json.dumps(request_body)
#Function to generate HMAC signature
def generate_hmac_signature(secret_key: str, req_body: str):
if isinstance(secret_key, str):
secret_key = secret_key.encode("utf-8")
if isinstance(req_body, str):
req_body = req_body.encode("utf-8")
hmac_obj = hmac.new(secret_key, req_body, hashlib.sha256)
hmac_digest = hmac_obj.digest()
hmac_signature = base64.urlsafe_b64encode(hmac_digest).decode()
return hmac_signature
hmac_signature = generate_hmac_signature(
secret_key=secret_key,
req_body=request_body,
)
#Passing the hmac signature in the headers
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
"X-BINDBEE-WEBHOOK-SIGNATURE": hmac_signature,
}
3. Include Signature in Request Headers
Once the signature is generated, WorkWise includes it in the headers of the webhook request. This allows TechCorp’s HR system to verify the authenticity of the webhook when it is received.
Here’s what the webhook request might look like with the signature:
POST /webhook/employee_update HTTP/1.1
Host: techcorp.com
Content-Type: application/json
X-Signature: 92f7d716849c1f4898ad076ce057492233cde8a7a45a790d89f0f963eb78c88c
The payload itself (e.g., John Doe’s promotion data) is sent in the body of the request, while the signature is sent in the X-Signature header.
4. Verify Signature on Receiving End
When TechCorp’s HR system receives the webhook, it needs to verify the signature to ensure that the payload hasn’t been tampered with.
To do this, TechCorp’s system takes the payload it received, rehashes it using the same hashing algorithm (SHA-256) and the same secret key (sK3j94vJg6dPqTx3c1)
.
If the system generates the same signature as the one included in the X-Signature header (92f7d716849c1f4898ad076ce057492233cde8a7a45a790d89f0f963eb78c88c)
, the webhook is verified as authentic.
Here’s how it would work out:
import base64
import hashlib
import hmac
secret_key = "sK3j94vJg6dPqTx3c1"
raw_request_body = request.body
# Reject any requests without a signature header present
try:
webhook_signature = request.headers["X-Bindbee-Webhook-Signature"]
except KeyError:
print('No signature sent, request did not originate from Bindbee.')
raise
# Encode request body in UTF-8 and generate an HMAC digest using the webhook signature
hmac_digest = hmac.new(secret_key.encode("utf-8"), raw_request_body.encode("utf-8"), hashlib.sha256).digest()
# The generated digest must be base64 encoded before comparing
b64_encoded = base64.urlsafe_b64encode(hmac_digest).decode()
# Use hmac.compare_digest() instead of string comparison to prevent against timing attacks
doesSignatureMatch = hmac.compare_digest(b64_encoded, webhook_signature)
- Payload received:
{"event": "employee.promoted", "employee_id": "12345", "employee_name": "John Doe", "new_position": "Senior Developer"}
- Secret key:
sK3j94vJg6dPqTx3c1
- Hash function: SHA-256
- Generated signature on TechCorp’s side:
92f7d716849c1f4898ad076ce057492233cde8a7a45a790d89f0f963eb78c88c
If the two signatures match, TechCorp’s HR system knows that the webhook is legitimate and processes the promotion event for John Doe. If they don’t match, the system discards the webhook, preventing any potential tampering.
5. Reject Invalid Requests
If the signature verification fails - whether due to payload tampering or a mismatch in the secret key—TechCorp’s HR system should reject the request.
For example, if an attacker tried to send a fake promotion event to the HR system, they wouldn’t have access to the secret key.
Therefore, the signature generated from the altered payload wouldn’t match the legitimate signature generated by WorkWise, and the request would be flagged as invalid.
TechCorp’s HR system could respond with a 401 Unauthorized status, log the invalid request for further investigation, and avoid processing any suspicious data.
Why Bindbee Use HMAC for Securing Webhooks
The decision to use HMAC at Bindbee was based on several key benefits:
- Simplicity: HMAC is easy to implement with minimal overhead. All that’s needed is a shared secret and a cryptographic hash function, making it accessible for various systems.
- Speed: HMAC is computationally efficient, even in high-traffic environments. It doesn’t slow down the transmission of webhook data, making it ideal for real-time applications.
- Proven Security: HMAC is a trusted standard in secure communication protocols, including TLS (used in HTTPS). Its widespread adoption across industries proves its effectiveness in preventing data breaches and message tampering.
Best Practices for Implementing HMAC
- Rotate Secrets Regularly: Change your secret keys periodically to minimize the risk of exposure.
- Use Strong Hash Functions: Opt for cryptographic hash functions like SHA-256 or SHA-512, which are more resistant to attacks.
- Log Failed Verification Attempts: Keep a log of all failed webhook verifications to identify potential attacks.
- Limit IP Addresses: Restrict webhook requests to come only from known IP addresses for an extra layer of security.
Takeaways
You’ve now well-aware of the in’s and out’s of security concerns in the connectivity space and how a technique like HMAC goes a long way to protect your organization’s PII from malicious interference or tampering.
At Bindbee, we’ve gone the extra mile to implement HMAC to prioritize the security concerns of both our customers and their end users. By incorporating HMAC for webhook verification, we prevent unauthorized access, secure your data, and maintain the integrity of all our customers’ operations.
If you’d like to explore more ways to secure your integrations and workflows, feel free to reach out to us.
Skip the wait, Book a Demo today!