Sqreen Webhooks


Note: The webhook v1 documentation is available here: webhook v1 documentation

Overview

The Sqreen event’s webhook allows Sqreen customers to receive real-time information about events detected by Sqreen.

The integration allows users, for example, to:

  • get notified when a user repeatedly fails to login, which can be useful to monitor your VIP customers
  • get notified when a user is sharing his account
  • get notified when a user performs an attack
  • get notified when Sqreen detect some major events
  • get notified when an account is compromised

Note: all the data presented featured this guide have been randomly generated.

Configuration

Visit your application settings to configure your webhook URL and the secret to verify it's sent from Sqreen. It's highly recommended to use an HTTPS endpoint.

You can configure a different webhook URL / secret per application in your Sqreen account.

webhook-config.png

Once configured, you can then review each security plugin from your Security Hub to decide which ones should ping your webhook when detecting security events. For instance, for the MongoDB injection plugin:

security-plugin-webhook-configuration.png

Webhook specification

Format

The webhook posts data to the URL you provided in the configuration. The body is encoded in JSON, which is indicated by the application/json content-type, with UTF-8 encoding (as stated in RFC 4627).

Payload types

Sqreen can send a few different payload types to your application. Each call to the webhook URL will send an array of payloads. All the payload have the same base structure:

  • message_id - Unique ID of the webhook
  • api_version - 2
  • date_created - Date in UTC (isoformat) when the webhook was sent
  • message_type - Type of message (see below)
  • retry_count - Number of time the message was sent
  • message - Actual payload data

Currently the type of these messages matches the objects that can be found in the Dashboard:

message_type description volume
security_event A security event as seen in Sqreen interface High volume
other An incident event as seen in Sqreen interface. Can be (account_takeover, http_scan, ...) depending of the incident Low volume
security_response A security response triggered when a playbook is configured to send a webhook Medium volume
test Test payload on demand

The maximum size of the array of payloads is 1k of events and will be split through multiple requests if necessary.

Security Events

A security event is the smaller piece of information the webhook provides you. This webhook provides information about the following events categories:

Event description Category
User related authentication
Injection related attacks occurring in your application injection
HTTP scanners targeting your application http_error
Vulnerable packages in your application package

Each category has sub-categories, e.g. on authentication:

Description Subcategory
Targeted account takeover tentative auth_ato_attempt
Successful account takeover auth_ato_success
Connection from a new location auth_new_location
Connection tentative from TOR auth_tor_tentative
Simulatenous connection from multiple locations auth_multi_locations

If one of these event category and kind is unknown or unused by your code, it should be ignored.

Payload structure

Each security event has the following structure:

  • event_category
  • event_kind
  • risk_coefficient
  • date_occured
  • humanized_description
  • application_id
  • application_name
  • environment
  • ips: array of
    • address
    • format
    • country_code
    • city
    • geo_longitude
    • geo_latitude
  • event_id
  • event_url

The maximum size of the array is of 1k events and will be split through multiple requests if necessary.

[{
  "message_id": "5de50f9bf681244a8cbf68f5",
  "api_version": "2",
  "date_created": "2019-12-02T13:18:21.708110+00:00",
  "message_type": "security_event",
  "retry_count": 0,
  "message": {
    "application_id": "587b23384891d57c1bf5bf4f",
    "application_name": "Demo app",
    "environment": "production",
    "date_occurred": "2016-12-21T07:22:32.732000+00:00",
    "event_category": "authentication",
    "event_id": "587b234e4891d57c1bf5c8c9",
    "event_kind": "auth_tor_tentative",
    "event_url": "https://my.sqreen.com/application/d8b47501fad44fb28d09967e1f1b09a258d85f4ba5d44e759b886f9663e7cf01/events/587b234e4891d57c1bf5c8c9",
    "humanized_description": "Connection to jeff45@harrell.com from TOR (135.96.171.118)",
    "ips": [
      {
        "address": "135.96.171.118",
        "date_resolved": "2017-01-15T07:22:54.573000+00:00",
        "geo": {
          "city": "Sag",
          "code": "ROU",
          "point": [
            21.283300399780273,
            46.04999923706055
          ]
        },
        "is_tor": true
      }
    ]
  }
}]

Incidents

An incident corresponds to a significant or group of significant security events happening on an application. This webhook provides information about the following incident categories:

message_type title
vulnerable_packages Vulnerabilities detected in your dependencies
injection_* Injection triggered by the RASP
http_scan Massive security scan has been {blocked
user_risk_increased The risk score of {account} exceeded {threshold}%
account_takeover Successful account takeover attempt on user account {account}

Payload structure

Each incident has the following structure:

  • incident_thread (ID of the event)
  • incident_status (Updated or created)
  • date_started
  • date_last_updated
  • application_id
  • new_related_ips: array of
    • address
    • format
    • country_code
    • city
    • geo_longitude
    • geo_latitude
  • new_compromised_account: array of
    • sqreen_id
    • user_identifiers
    • ip_address
{
  "message_id": "5de52295f68124623a7f16f5",
  "api_version": "2",
  "date_created": "2019-12-02T14:38:31.486469+00:00",
  "message_type": "account_takeover",
  "retry_count": 0,
  "message": {
    "incident_thread": "track_collection_7c21d0f112098078dc19ca458f74a184",
    "incident_status": "created",
    "date_started": "2019-12-02T13:34:42.908000+00:00",
    "date_last_updated": "2019-12-02T13:36:24.449000+00:00",
    "application_id": "587b23384891d57c1bf5bf4f",
    "new_related_ips": [
      {
        "address": "135.96.171.118",
        "date_resolved": "2017-01-15T07:22:54.573000+00:00",
        "geo": {
          "city": "Sag",
          "code": "ROU",
          "point": [
            21.283300399780273,
            46.04999923706055
          ]
        },
        "date_resolved": "2019-12-02T12:53:09.094000+00:00",
        "vpn": false,
        "proxy": false,
        "datacenter": false,
        "metadata": {
          "version": 4,
          "multicast": false,
          "private": false,
          "global": true,
          "unspecified": false,
          "reserved": false,
          "loopback": false
        },
        "tags": []
      }
    ],
    "new_compromised_accounts": [
      {
        "sqreen_id": "W1siZW1haWwiLCAiZm9vQGJhci5iYXoiXV0=",
        "user_identifiers": {
          "email": "foo@bar.baz"
        },
        "ip_address": "135.96.171.118"
      }
    ]
  }
}

Security Automation response

A security response payload will be sent every time a Security Playbook triggers.

Payload structure

[
  {
    "id": "5de51a89f681245ab970ad66",
    "message_type": "security_response",
    "retry_count": 2,
    "date_created": "2018-07-20T12:01:17.374627+00:00",
    "message": {
      "application": {
        "name": "Application name",
        "environment": "production",
        "id": "5a87625fcefe8b16933724"
      },
      "properties": {
        "ips": [
          {
            "ip_cidr": "172.17.0.1/32"
          }
        ],
        "user_identifiers": [
          {
            "email": "user@sqreen.com"
          }
        ]
      },
      "playbook": {
        "name": "Peak of login failure",
        "id": "5b3e2b316964a8001b500ca2"
      }
    }
  }
]

Return value

When a payload is posted to the URL provided, the returned HTTP code is interpreted in this way:

  • successful if HTTP code is in range [200, 299];
  • failure otherwise.

Sqreen won’t follow any redirects to your application.

Signature

The secret given in the configuration page is intended to sign the request body. This signature is placed in the X-Sqreen-Integrity header.

The signature algorithm is an HMAC with the SHA-256 digest.

Example for the key 1234:

POST /some/url HTTP/1.1
...
X-Sqreen-Integrity: 9d101d2bf630748679226b767d2031634c520390ff0e926afc09bc65a05bfdb2
...
4567
require 'openssl'

def check_signature(secret_key, request_signature, request_body)

  digest = OpenSSL::Digest.new('sha256')

  hmac = OpenSSL::HMAC.new(secret_key, digest)
  hmac.update(request_body)
  hmac.to_s == request_signature
end

# req_sig = request.headers['X-Sqreen-Integrity']
# req_body = request.body.read
# secret_key = ENV['SQREEN_WEBHOOK_KEY']

req_sig = '9d101d2bf630748679226b767d2031634c520390ff0e926afc09bc65a05bfdb2'
req_body = '4567'
secret_key = '1234'

puts check_signature(secret_key, req_sig, req_body)
import hmac
import hashlib

def check_signature(secret_key, request_signature, request_body):

    hasher = hmac.new(secret_key, request_body, hashlib.sha256)
    dig = hasher.hexdigest()

    return hmac.compare_digest(dig, request_signature)

# for Flask:
# request_body = request.get_data()
# request_signature = request.headers['X-Sqreen-Integrity']

# for Django:
# request_body = request.request_body
# request_signature = request.META['X-Sqreen-Integrity']

req_sig = '9d101d2bf630748679226b767d2031634c520390ff0e926afc09bc65a05bfdb2'
req_body = b'4567'
secret_key = b'1234'

print(check_signature(secret_key, req_sig, req_body))

More examples

Connection from new location

[{
  "id": "5de51ae9f681245ab970ad67",
  "message_type": "security_event",
  "retry_count": 1,
  "date_created": "2017-01-04T07:22:32.732000+00:00",
  "message": {
    "application_id": "587b23384891d57c1bf5bf4f",
    "application_name": "Demo app",
    "environment": "production",
    "date_occurred": "2017-01-04T07:22:32.732000+00:00",
    "event_category": "authentication",
    "event_id": "587b234b4891d57c1bf5c766",
    "event_kind": "auth_new_location",
    "event_url": "https://my.sqreen.com/application/d8b47501fad44fb28d09967e1f1b09a258d85f4ba5d44e759b886f9663e7cf01/events/587b234b4891d57c1bf5c766",
    "humanized_description": "Connection to tsanchez@yahoo.com from Sag, Romania",
    "ips": [
      {
        "address": "84.185.129.221",
        "date_resolved": "2017-01-15T07:22:51.494000+00:00",
        "geo": {
          "city": "Sag",
          "code": "ROU",
          "point": [
            21.283300399780273,
            46.04999923706055
          ]
        },
        "is_tor": false
      }
    ]
  }
}]

Massive security scan

[{
  "message_id": "5de51b8af681245ab970ad68",
  "api_version": "2",
  "date_created": "2019-12-02T14:04:49.455514+00:00",
  "message_type": "http_scan",
  "retry_count": 0,
  "message": {
    "incident_thread": "in_7493f8e8c6084457a6e5a38af2ddbd31",
    "incident_status": "created",
    "date_started": "2017-10-17T14:03:00+00:00",
    "date_last_updated": "2017-10-17T15:20:35.129000+00:00",
    "application_id": "587b23384891d57c1bf5bf4f",
    "new_related_ips": [
      {
        "address": "84.185.129.221",
        "date_resolved": "2017-01-15T07:22:51.494000+00:00",
        "geo": {
          "city": "Sag",
          "code": "ROU",
          "point": [
            21.283300399780273,
            46.04999923706055
          ]
        },
        "is_tor": false
      }
    ]
  }
}]

SQL Injection

[{
  "message_id": "5de51c15f681245ab970ad69",
  "api_version": "2",
  "date_created": "2019-12-02T14:12:44.581570+00:00",
  "message_type": "injection_sql",
  "retry_count": 0,
  "message": {
    "incident_thread": "track_collection_98b9f15eb0c0eb87580d7d662e108e26",
    "incident_status": "created",
    "date_started": "2019-11-14T13:46:36.764000+00:00",
    "date_last_updated": "2019-11-14T13:57:55.377000+00:00",
    "application_id": "587b23384891d57c1bf5bf4f",
    "new_related_ips": [
      {
        "is_tor": false,
        "date_resolved": "2019-11-14T08:57:52.600000+00:00",
        "proxy": false,
        "metadata": {
          "version": 4,
          "multicast": false,
          "private": true,
          "global": false,
          "unspecified": false,
          "reserved": false,
          "loopback": true
        },
        "geo": {},
        "vpn": false,
        "address": "127.0.0.1",
        "tags": [
          "private"
        ],
        "datacenter": false
      }
    ]
  }
}]