Sqreen Webhooks¶ Webhooks v1 deprecated Sqreen Webhooks v1 is deprecated. However, the documentation remains available. Use Sqreen Webhooks to send Sqreen security data to a third-party tool. In your Sqreen Dashboard, you can configure the conditions in which Sqreen sends a notification to a third-party tool in the form of an HTTP POST request. For example, when Sqreen detects that a user has repeatedly failed to login, it can POST a message to the Pager Duty REST API with the details of the security incident. Configure a webhook¶ In the Sqreen Dashboard, from the application to connect, navigate to Settings > Integrations. In the Webhook pane, enter the URL. It's the destination to which you wish to POST messages from Sqreen (https://example.com/postreceive). Retrieve the secret. This secret will be used to validate the message was emitted by Sqreen. Test, then Save the configuration. Navigate to your Protection modules to select a particular protection and adjust its settings to send data to the webhook URL. For example, navigate to Configuration > Runtime Application Self-Protection > Shell Injection. Use the interface to adjust the settings. If you use Security Automation Playbooks in Sqreen, navigate to Playbooks in your Sqreen Dashboard to create a new playbook and set the notification to send data to the webhook URL. Webhook request specifications¶ The body of each request Sqreen sends to a third-party receiver is encoded in JSON, as indicated by the content-type application/json with UTF-8 encoding (as per RFC 4627). The maximum size of the array of payloads is 1000 events; Sqreen splits the payload into multiple requests if necessary. The payloads of each HTTP POST request have the same basic structure. message_id - unique ID of the webhook api_version - version of the api date_created - date in UTC (isoformat) indicating when Sqreen sent the request message_type - type of message (see section below) retry_count - number of times Sqreen sent the request message - payload data Message types¶ The message_type matches an object in the Sqreen Dashboard. The volume corresponds to the severity of the conditions which trigger Sqreen to send the notification/HTTP request (High, Medium, Low). Message type Description Volume security_event a security event as seen in the Sqreen Dashboard high other an Incident as seen in the Sqreen Dashboard, such as a brute force attack low security_response a security response that Sqreen sends when user activity triggers a playbook medium test test payload on demand Security event¶ Sqreen Webhook provides information about the following event categories: Category Description authentication user-related activity in your application injection injection-related attacks occurring in your application http_error HTTP scanners targeting your application package vulnerable packages in your application Each event category has sub-categories. The table below uses the example category authentication. Sub-category Description auth_ato_attempt targeted account takeover tentative auth_ato_success successful account takeover auth_new_location connection from a new location auth_tor_tentative connection tentative from TOR auth_multi_locations simultaneous connection from multiple locations Each security event has the following message payload structure. application_id application_name environment date_occured event_category event_id event_kind event_url humanized_description ips: array of address date_resolved city country_code geo_longitude geo_latitude is_tor [{ "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 } ] } }] Other¶ An Incident (other message type) corresponds to a significant security event or group of events occurring in an application. Sqreen Webhook provides information about the following event categories: Category Description vulnerable_packages vulnerabilities detected in your dependencies injection_* injection triggered by the RASP http_scan a massive security scan has been {detected user_risk_increased risk score of {account} exceeded {threshold}% account_takeover successful account takeover attempt on user {account} Each incident has the following message payload 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 date_resolved city country_code 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 response¶ Sqreen sends a security response payload each time user activity triggers a Security Automation Playbook. Each incident has the following message payload structure. application name environment id properties ips user_identifiers playbook name id [ { "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" } } } ] HTTP response¶ When Sqreen posts a request to webhook's URL, it interprets the returned HTTP status code according to the table below. Sqreen does not follow any redirects to your application. HTTP code Interpretation range [200, 299] success all else fail Signature¶ Sqreen uses the Secret Key provided when you configured the webhook to sign the HTTP request body. The signature is 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 Ruby: 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) Python: 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)) Node.js: const crypto = require('crypto'); function check_signature(secret_key, request_signature, request_body) { const digest = crypto.createHmac('sha256', secret_key) .update(request_body) .digest(); return crypto.timingSafeEqual(digest, Buffer.from(request_signature, 'hex')); } // for Express (needs a body parser middleware): // req_body = req.body; // req_sig = req.header('X-Sqreen-Integrity'); // secret_key = process.env.SQREEN_WEBHOOK_KEY; const req_sig = '9d101d2bf630748679226b767d2031634c520390ff0e926afc09bc65a05bfdb2'; const req_body = '4567'; const secret_key = '1234'; console.log(check_signature(secret_key, req_sig, req_body)); Example: 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 } ] } }] Example: 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 } ] } }] Example: 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 } ] } }]