在 Python Flask 中验证来自 Microsoft Teams 机器人的 HMAC

Verifying HMAC from Microsoft Teams bot in Python Flask

我正尝试按照 how to build custom bots 上的说明使用 Flask 构建 Microsoft Teams 聊天机器人。但是我无法验证我真正想要的安全性的 HMAC 身份验证。

根据指南和文档,我发现我正在使用以下最小测试应用程序来尝试计算传入请求的 HMAC。 (机器人名称和描述 DevBot 以及下面的 key/security_token 用于测试)。

#!/usr/bin/python
# coding=utf-8

from flask import Flask, request, jsonify
import hmac, hashlib, base64, json

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def webhook():
    if request.method == 'POST':

        # Authenticate
        security_token = b"O5XHU8OSzwx8w9YiM0URkR/Ij4TZZiZUwz7Swc+1hZE="
        request_data = request.get_data()
        digest = hmac.new(security_token, msg=request_data, digestmod=hashlib.sha256).digest()
        signature = base64.b64encode(digest).decode()


        # TODO: Verify signature = Authorization header HMAC here

        return jsonify({
            'type' : 'message',
            'text' : "Auth header: {0} <br>Calculated HMAC: {1}".format(request.headers.get('Authorization'), signature),
        })

    elif request.method == 'GET':
        return "Hello World"


if __name__ == '__main__':
    app.run(debug=True)

发送消息后 @DevBot test 我在机器人的回复中得到了以下哈希值,但它们与预期的不匹配:

Auth header: HMAC LuDmz97y/Z2KWLIZ1WZASz3HlOEtDCwk5/lL/fK8GqM= 
Calculated HMAC: eaxTdJSLuU3Z4l94bxFiWvsBhjNG9SPxwq/UHeR7KcA= 

有什么想法或建议吗?我一直在尝试各种编码方法,但我觉得 Flask 可能会做一些修改请求正文的事情?

编辑 1:小澄清

编辑 2:完整的 Flask 应用示例

编辑 3:示例机器人详细信息、输入和输出示例

除了直接与 Microsoft Teams 交互之外,另一种选择可能是使用 Microsoft Bot Connector API。

https://docs.botframework.com/en-us/restapi/connector/

我有一个使用 https://github.com/Grungnie/microsoftbotframework 与 Microsoft Teams 合作的机器人,它正在验证从 Microsoft 发送的 JWT。

经过大量试验和错误并尝试从 MS 重现 C# 代码示例后,我设法自己解决了它。解决方法如下:

#!/usr/bin/python
# coding=utf-8

from flask import Flask, request, jsonify
import hmac, hashlib, base64, json

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def webhook():
    if request.method == 'POST':


        # Reply
        data = request.get_json()
        channel = data['channelId']
        message_type = data['type']
        sender = data['from']['name']
        message_format = data['textFormat']
        message = data['text']

        # Authenticate

        security_token = b"O5XHU8OSzwx8w9YiM0URkR/Ij4TZZiZUwz7Swc+1hZE="
        request_data = request.get_data()
        digest = hmac.new(base64.b64decode(security_token), msg=request_data, digestmod=hashlib.sha256).digest()
        signature = base64.b64encode(digest).decode()

        # TODO: verify that HMAC header == signature

        return jsonify({
            'type' : 'message',
            'text' : "auth header: {0} <br>hmac: {1}".format(request.headers.get('Authorization').split(' ')[1], signature),
        })

    elif request.method == 'GET':
        return "Hello World"


if __name__ == '__main__':
    app.run(debug=True)