Как проверить подпись почтового запроса с помощью flask/python, когда документация написана на Ruby

Я пытаюсь проверить подпись почтового запроса, и пока хэш подписи не соответствует тестовому хэшу, который я генерирую с помощью моего API-интерфейса фляги.

В документах указан следующий код для проверки подписи в Ruby.

payload_body = request.body.read

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

Вот что я собрал во 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()

Со следующими данными:

СЕКРЕТ_ТОКЕН=""

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

Они получают:

Рубиновый хеш: "sha1=2e7c4e307e25dd0ce4baad4d90dc7d4b63bdbab6" # как указано в документации

я получаю:

Хэш Python: "sha1=b9361bca2a38228c741ef60296b468693752b76d" # моя реализация

Любая помощь/указатели будут очень признательны!

Официальный документ находится здесь: https://docs.developer.fractal.id/user-integration/webhooks/securing-webhooks и https://docs.developer.fractal.id/user-integration/webhooks/delivery


person Hossayne Tahiri    schedule 18.05.2020    source источник
comment
Не могли бы вы предоставить ссылку на документацию, на которую вы ссылаетесь? Некоторый дополнительный контекст может быть полезен.   -  person alexdlaird    schedule 18.05.2020
comment
Попробуйте использовать Flask request.data вместо request.get_data. Возможно, это связано с тем, как JSON кодируется/добавляет escape-символы при преобразовании его в строку (что, очевидно, испортит полученный хэш).   -  person alexdlaird    schedule 19.05.2020
comment
Пробовал request.data и request.stream.read(), но ничего   -  person Hossayne Tahiri    schedule 19.05.2020


Ответы (1)


Основываясь на предоставленной документации, я бы реализовал такую ​​проверку подписи HMAC SHA1 (это очень похоже на то, как GitHub делает веб-перехватчики, и эта реализация работает там, но я обновил заголовки, чтобы они соответствовали тому, что вы ожидаете) :

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)

В документации они прерывают 400, лично я бы вместо этого использовал 403.

person alexdlaird    schedule 18.05.2020
comment
Спасибо за ответ! Однако моя проблема заключается не в реализации фляги. То, что вы предлагаете, даст тот же результат, что и мой, для подписи с учетом полезной нагрузки и секретного токена: b9361bca2a38228c741ef60296b468693752b76d. Но официальный документ находит: 2e7c4e307e25dd0ce4baad4d90dc7d4b63bdbab6. Еще раз спасибо за вашу очень долгожданную помощь - person Hossayne Tahiri; 18.05.2020
comment
Запуск собственного примера Ruby (или сброс секрета/полезной нагрузки в онлайн-генератор HMAC) не приводит к SHA1, который они предоставляют в своем примере, и, учитывая, что их документы говорят, что они в значительной степени WIP, я готов поспорить это просто плохой пример. Выше приведен рабочий пример Flask для другой проверки веб-перехватчика, которая соответствует тем же критериям, поэтому я бы пошел с ним и посмотрел, не произойдет ли сбой при интеграции — если это произойдет, я думаю, вам нужно будет обсудить это с ними. - person alexdlaird; 19.05.2020
comment
Почти уверен, что правильный хэш должен быть ba213ac630ca4e30446a923fdd1fa78655902880, что и дал пример, который я вам дал. - person alexdlaird; 19.05.2020