Overview

A webhook action sends a notification to a URL of your choosing when one or more rules with the action flag an email message. The HTTP notification includes information about the message, the mailbox, and the flagged rules, so you can set up an unlimited variety of integrations in response to flagged message events.

Here is some of what you can do with webhooks:

  • Send Flagged Message events to your SIEM for analytics or to correlate with events from other tools, such as your EDR
  • Send Flagged Message events to your SOAR, to trigger sophisticated DFIR workflows that are today only used on reported phish
  • Trigger an AWS Lambda function

How to create a Webhook action

  1. Set up the endpoint URL in the external system that you want to send Flagged Message events to (e.g. your SIEM, SOAR, or an intermediary like AWS Lambda or Zapier). Some systems call an integration that provides a URL for receiving webhook notifications a "webhook integration".
  2. Go to your Sublime Dashboard and click "Actions"
  3. Click "New action" and select "Webhook"
  4. Give your webhook a name, provide the endpoint URL you generated externally in step 1, and optionally specify custom headers that will be included in the HTTP request for webhook notifications
  5. Click "Save"

How to add your new Webhook action to Rules

  1. Click "My Rules" in the left nav of your Dashboard
  2. Click on the rule you wish to add the action to, opening the detail view for this rule
  3. Click "Edit" in the top right of this detail view
  4. Click "Save Rule"
  5. Click the "Actions" dropdown and select your new webhook action
  6. Click "Save Rule"

Custom headers

Any custom headers you configure for your webhook actions will be be included in the HTTP requests for webhook notifications. You can include as many custom headers as you need.

The webhook payload

Once you activate a webhook action and connect it to a rule, whenever that rule flags a message, the endpoint for the webhook will receive an HTTP POST request with a body like the following:

{
    "id": "5e02026c-55c1-4cbb-8a18-76eb2f3e06d3",
    "api_version": "0",
    "created_at": "2021-06-30T16:17:22.937642Z",
    "type": "message.flagged",
    "data": {
        "message": {
            "id": "dff3be1d-b348-4dab-bb60-582842909a88",
            "canonical_id": "767f6519458092af9994a79ae73ca055e1365618",
            "external_id": "17a5db5ea7fa760d",
            "message_source_id": "a5843e7d-4ba5-40df-954e-73cb2f1e3e7e"
        },         
        "flagged_rules": [
            {
                "id": "756b841c-4560-49b3-a8c0-dbacb2900aa5",
                "name": "Brand impersonation: Chase Bank",
                "tags": [
                    "brand-impersonation",
                    "suspicious-sender"
                ]
            },
            {
                "id": "67cfc6d8-3cbb-4338-ae8e-fffb0adccd12",
                "name": "Firebase storage link",
                "tags": [
                    "suspicious-content"
                ]
            }
        ]
    }
}

Responding to webhook notifications

The endpoint URL you configure for a webhook should respond to the webhook's HTTP requests with an HTTP response code starting with 2 (for example, 200) within 10 seconds. If your integration needs to do anything in response to webhook notifications that may take more than 10 seconds, it should send an HTTP response before doing that work.

Check the webhook signature

Webhook notifications include a signature in the X-Sublime-Signature HTTP header. This allows you to verify that the requests were sent by Sublime, not some other party.

Before you can verify signatures, you need to retrieve your webhook action's signing secret. Select a webhook action from the "Actions" page, then click "Click to reveal", or click the "Copy" button to copy the secret directly to your clipboard.

The X-Sublime-Signature header included in each request contains a timestamp and one or more signatures. The timestamp is prefixed by t=, and each signature is prefixed by a scheme. Schemes start with v, followed by an integer. Currently, the only valid signature scheme is v0.

t=1626139320,v0=3d35d777510a7ccf73ded723f141b0ada2986aebe63c4e45a9c7e4bb1abaca06

Sublime generates signatures using a hash-based message authentication code (HMAC) with SHA-256. To prevent downgrade attacks, you should ignore all schemes that are not v0.

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, Sublime includes a timestamp in the X-Sublime-Signature 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.

Sublime generates the timestamp and signature each time a webhook notification is sent to your endpoint. If Sublime retries a notification (for example, 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

Follow these steps to verify a request's signature:

Step 1: Extract the timestamp and signatures from the header

Split the header, using the , character as the separator, to get a list of elements. Then split each element, using the = character as the separator, to get a prefix and value pair.

The value for the prefix t corresponds to the timestamp, and v0 corresponds to the signature (or signatures). You can discard all other elements.

Step 2: Prepare the signed_payload string

The signed_payload string is created by concatenating:

  1. The timestamp (as a string)
  2. The character .
  3. The actual JSON payload (that is, the request body)

Step 3: Determine the expected signature

Compute an HMAC with the SHA256 hash function. Use the webhook'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.