Hossayne Tahiri
Hossayne Tahiri

Reputation: 11

How to verify a post request signature using flask/python when documentation is in Ruby

I am trying to validate a post request signature and so far the signature hash is not matching the test hash i'm generating through my flask api.

The docs list the following code to verify the signature in Ruby

payload_body = request.body.read

signature = "sha1=" + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha1"), SECRET_TOKEN, payload_body)

This is what I have put together so far in Flask/Python 3.6:

import hashlib, hmac

data=request.get_data()
key=SECRET_TOKEN.encode("utf-8"))
signature = "sha1=" + hmac.new(key, data, hashlib.sha1).hexdigest()

With the following data:

SECRET_TOKEN=""

request_data={"type": "verification_approved","data":{"level":"v1","user_id":"d6d782ef-568b-4355-8eb4-2d32ac97b44c"}}

They obtain :

Ruby hash: "sha1=2e7c4e307e25dd0ce4baad4d90dc7d4b63bdbab6" # as indicated in the documentation

I obtain:

Python hash: "sha1=b9361bca2a38228c741ef60296b468693752b76d" # my implementation

Any help/pointers would be greatly appreciated!

Official doc is here: https://docs.developer.fractal.id/user-integration/webhooks/securing-webhooks and https://docs.developer.fractal.id/user-integration/webhooks/delivery

Upvotes: 1

Views: 2724

Answers (1)

alexdlaird
alexdlaird

Reputation: 1293

Based on the documentation given, this is how I would implement such a HMAC SHA1 signature validation (this is very similar to how GitHub does webhooks, and this implementation works there, but I've updated the headers to match what you're expecting):

import hmac
from hashlib import sha1

from flask import request, abort

@app.route("/webhook", methods=["POST"])
def webhook(request):
    if "X-Fractal-Signature" not in request.headers:
        abort(403)
    signature = request.headers.get("X-Fractal-Signature", "").split("=")[1]

    # Generate our own signature based on the request payload
    secret = os.environ.get('FRACTAL_SECRET', '').encode("utf-8")
    mac = hmac.new(secret, msg=request.data, digestmod=sha1)

    # Ensure the two signatures match
    if not str(mac.hexdigest()) == str(signature):
        abort(403)

They abort a 400 in the documentation, personally I'd use a 403s instead.

Upvotes: 2

Related Questions