Topics on this page
Secure web hooks
Deep Security Smart Check gives you an easy way to ensure that the events that your web server is receiving are coming from Deep Security Smart Check and have not been modified in transit.
When Deep Security Smart Check calls back to your server, it computes a signature (HMAC-SHA-256) for the event using the secret as the key and puts the signature value in the X-Scan-Event-Signature
HTTP header.
The request that your server gets look like this:
POST https://server.example.com/ HTTP/1.1
X-Scan-Event-Signature: {signature}
Content-Type: application/json
{
"event": "scan-completed",
"source": "/api/webhooks/7a2f1d8c-7780-41d2-821b-7230005d4be8",
"timestamp": "2018-05-01T00:00:00Z",
"scan": {
...
}
}
The value of the scan
attribute is the scan details object as detailed in the API documentation.
Create the web hook
When you create the web hook, set the secret
attribute to a value that only Deep Security Smart Check and your server will know. In this example, we're using correct horse battery staple
as our shared secret, but you should use a long string of random characters.
POST https://dssc.example.com/api/webhooks HTTP/1.1
Authorization: Bearer {token}
Content-Type: application/json
{
"name": "secure webhook",
"hookUrl": "https://server.example.com/",
"active": true,
"events": [ "*" ],
"secret": "correct horse battery staple",
}
Calculate and check the signature
To check the signature, compute the HMAC-SHA-256 signature of the payload using the secret as the key and compare it with the value in the X-Scan-Event-Signature
HTTP header. In this example, the secret is stored in the HMAC_SECRET
environment variable.
export HMAC_SECRET="correct horse battery staple"
# Get the secret from the environment -- don't store it in code!
secret = os.environ.get('HMAC_SECRET')
# Get the size of the payload
content_length = int(self.headers.get('Content-Length', 0))
if content_length == 0 or content_length > MAX_PAYLOAD_SIZE:
raise InvalidPayloadSizeException()
# Read the full event payload from the request
payload = self.rfile.read(content_length)
# Calculate the HMAC-SHA-256 signature of the payload using the secret as the HMAC key
actual = hmac.new(bytes(secret, 'utf-8'),
msg=bytes(payload),
digestmod=hashlib.sha256).hexdigest()
# Get the expected HMAC-SHA-256 signature value from the request header
expected = self.headers.get('X-Scan-Event-Signature', '')
# Use compare_digest to reduce vulnerability to timing attacks
if not hmac.compare_digest(actual, expected):
# the event has been tampered with or is not from the right sender
Send a test event
You can use the web hook ping
API endpoint to send a test event to your web hook:
POST https://dssc.example.com/api/webhooks/7a2f1d8c-7780-41d2-821b-7230005d4be8/ping HTTP/1.1
Authorization: Bearer {token}
Deep Security Smart Check will send a sample event that looks similar to this:
POST https://server.example.com/ HTTP/1.1
X-Scan-Event-Signature: {signature}
Content-Type: application/json
{
"event": "ping",
"source": "/api/webhooks/7a2f1d8c-7780-41d2-821b-7230005d4be8",
"timestamp": "2018-05-01T00:00:00Z",
}
and you can confirm that your validation code works as expected.