-
-
Save johnnyman727/410892197f57f2bf99d499fc7e407369 to your computer and use it in GitHub Desktop.
Python Webhook signature validation for Arc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import hashlib | |
import hmac | |
import time | |
import starlette | |
WEBHOOK_SIGNING_KEY = "<YOUR_WEBHOOK_SIGNING_KEY>" | |
SECONDS_TO_STALE = 300 # 5 minutes | |
class ArcadiaSignatureException(Exception): | |
pass | |
async def validate_webhook_signature(req: starlette.requests.Request): | |
req_body = await req.body() | |
now_ts = time.time() | |
# 1. Extract the timestamp and signatures from the header | |
webhook_ts = int(req.headers.get("Arc-Webhook-Timestamp", 0)) | |
webhook_signature = req.headers.get("Arc-Webhook-Signature", "") | |
if not webhook_ts or not webhook_signature: | |
raise ArcadiaSignatureException | |
# 2. Prepare the payload string by concatenating the timestamp with the body | |
payload_to_sign = f"{webhook_ts}.{req_body.decode()}" | |
# 3. Calculate the Signature using your Arcadia Webhook Secret | |
signature = hmac.new( | |
bytes(WEBHOOK_SIGNING_KEY, "utf-8"), msg=bytes(payload_to_sign, "utf-8"), digestmod=hashlib.sha256 | |
).hexdigest() | |
# 4. If the timestamp is older than the threshold, this may be a replay attack | |
if abs(now_ts - webhook_ts) > SECONDS_TO_STALE: | |
raise ArcadiaSignatureException | |
# 5. If the signatures don't match, this may be a fraudulent webhook | |
# Be sure to use a constant time string comparison algorithm to prevent timing attacks | |
if not hmac.compare_digest(signature, webhook_signature): | |
raise ArcadiaSignatureException |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment