How to ensure HTTP requests are coming from the Meya Bot Platform
In order to ensure that requests are coming from Meya Bot Platform and not a malicious third party, we have included a cryptographic signature.
This works very similar to how Twilio security works.
How Meya signs requests to your server
- Meya appends JSON body /w sorted keys, and spaces removed to the end of the URL (with no delimiter)
- Meya takes the resulting string (the full URL with query string and the raw body) and signs it using HMAC-SHA1 and your api_key as the key.
- Meya sends this signature in an HTTP header called
X-Meya-Signature
How to verify the signature
- Take the full URL of the request and append the JSON body /w sorted keys, and spaces removed as a string
- Sign the resulting string with HMAC-SHA1 using your
api_key
as the key - Base64 encode the resulting hash value
- Compare your hash to ours, submitted in the
X-Meya-Signature
header. If they match, then you've verified that Meya is the originator
Example headers
POST /yourpath HTTP/1.1
Host: yourdomain.com
Accept-Encoding: gzip, deflate
Accept: application/json
User-Agent: python-requests/2.13.0
X-Meya-Signature: Wrl+9YX4ok2RI0VAugSwKcVWgto=
Content-Type: application/json
Content-Length: 130
X-Forwarded-Proto: https
X-Forwarded-For: 52.91.53.134
How to verify signature
from hashlib import sha1
import hmac
import json
API_KEY = "a6xE5yLe0RHPYbiHqR3OKDmRgsZ76RY3"
"""
Verify with the following data:
url = "https://203f31bb.ngrok.io/rx/apibot"
body = '{"user_id": "1234567890", "sender": "user", "timestamp": 1489843997.625053, "text": "hi", "type": "text", "bot_id": "BJty7evfw2b"}'
signature = "Wrl+9YX4ok2RI0VAugSwKcVWgto="
"""
def standardize_json_string(raw_body):
# ensure sorted keys and no separators
data = json.loads(raw_body)
return json.dumps(data, sort_keys=True, separators=(',', ':'))
def validate(request):
url = request.url
message = standardize_json_string(request.body)
signature = request.headers.get('X-Meya-Signature')
data = str(url + message)
hashed = hmac.new(API_KEY, data, sha1)
computed_signature = hashed.digest().encode("base64").rstrip('\n')
return computed_signature == signature