Increase security by verifying that webhook events were sent by DigiFi (Recommended).

Overview

To let you verify that events were sent by DigiFi (not by a third party), DigiFi can optionally sign the webhook events it sends to your endpoints by including a signature in each event’s x-digifi-signature header.

You can verify signatures either using DigiFi's Official Node.js library, or using your own solution.

Before you can verify signatures, you need to retrieve your endpoint’s secret from within the DigiFi platform by navigating to this specific webhook and clicking on the "Integration" tab.

DigiFi generates a unique secret key for each endpoint. Additionally, if you use multiple endpoints, you must obtain a secret for each one you want to verify signatures on.

👍

Highly Recommended To Increase Security!

Security your endpoint provides increased security for your overall application. It is highly recommended that all organizations who implement DigiFi Webhooks secure their endpoints.


Verifying Signatures Using DigiFi's Node.js Library

When using DigiFi's library to verify signatures, you perform the verification by providing:

  • the event payload,
  • the x-digifi-signature header,
  • the x-digifi-event-timestamp, and
  • the endpoint’s secret.

If verification fails, DigiFi returns an error.

const express = require('express');
const digifi = require('digifi-node-js');
const bodyParser = require('body-parser');

const app = express();
const endpointSecret = '...';

app.post('/webhooks', bodyParser.raw({ type: 'application/json' }), (req, res) => {
  const timestamp = req.headers['x-digifi-event-timestamp'];
  const signature = req.headers['x-digifi-signature'];
  
  if (!digifi.verifyWebhookSignature(req.body, endpointSecret, timestamp, signature)) {
    res.status(400).send({ message: 'Invalid signature' });
    
    return;
  }
  
  if (!digifi.verifyWebhookTimestamp(timestamp)) {
    res.status(400).send({ message: 'Invalid timestamp' });
    
    return;
  }

  switch (req.body.eventType) {
    case 'application.created': {
      handleApplicationCreate();
    }
    case 'application.updated': {
      handleApplicationUpdate();
    }
  }

  res.status(200).send({});
});

app.listen(3000, () => {
  console.log(`Example app listening at http://localhost:3000`)
});

Preventing Replay Attacks

A replay attack is when an attacker intercepts a valid payload and its signature, then re-transmits them. To mitigate such attacks, DigiFi includes a timestamp in the x-digifi-event-timestamp header. Because this timestamp is part of the signed payload, it is also verified by the signature, so an attacker cannot change the timestamp without invalidating the signature. If the signature is valid but the timestamp is too old, you can have your application reject the payload.

Our libraries have a default tolerance of five minutes between the timestamp and the current time. You can change this tolerance by providing an additional parameter when verifying signatures. Use Network Time Protocol (NTP) to ensure that your server’s clock is accurate and synchronizes with the time on DigiFi's servers.

DigiFi generates the timestamp and signature each time an event is sent to your endpoint. If DigiFi retries an event (e.g., your endpoint previously replied with a non-2xx status code), then a new signature and timestamp is generated for the new delivery attempt.


Verifying Signatures Manually

DigiFi generates signatures using a hash-based message authentication code (HMAC) with SHA-256.

Although it’s recommended to use our official libraries to verify webhook event signatures, you can create a custom solution by following these steps.

Step 1: Extract The Timestamp And Signatures From The Header

Retrieve the x-digifi-event-timestamp and x-digifi-signature from request headers.

Step 2: Prepare The signed_payload String

The signed_payload string is created by concatenating:

  • The timestamp (as a string),
  • The character ".", and
  • The actual JSON payload (i.e., the request body)

Step 3: Determine The Expected Signature

Compute an HMAC with the SHA256 hash function. Use the endpoint’s signing secret as the key, and use the signed_payload string as the message.

Step 4: Compare The Signatures

Compare the signature (or signatures) in the header to the expected signature. For an equality match, compute the difference between the current timestamp and the received timestamp, then decide if the difference is within your tolerance.

To protect against timing attacks, use a constant-time string comparison to compare the expected signature to each of the received signatures.