0

我正在尝试从 Todoist 集成 Webhooks API。我得到了正确的标头和正文信息,但无法验证 X-Todoist-Hmac-SHA256 标头。来自 Todoist 文档:

为了验证每个 webhook 请求确实是由 Todoist 发送的,包含一个 X-Todoist-Hmac-SHA256 标头;它是使用您的client_secret作为加密密钥和整个请求有效负载作为要加密的消息生成的SHA256 Hmac 。生成的 Hmac 将被编码为 base64 字符串。

现在这是我使用 express.js 和 Node.js Crypto 库进行解密的 webhook 路由代码:

app.post("/webhooks/todoist", async (req, res) => {

    // this is my stored client secret from Todoist
    const secret = keys.todoistClientSecret 
    
    // Using the Node.js Crypto library
    const hash = crypto.createHmac('sha256', secret)
      .update(req.toString()) // <-- is this the "whole request payload"?
      .digest("base64");


    // These 2 are not equal
    console.log("X-Todoist-Hmac-SHA256:", req.header("X-Todoist-Hmac-SHA256"))
    console.log("Hash:", hash)

    res.status(200).send()
  })

我已经发现req 的类型是IncomingMessage。Crypto 库只接受某些类型,如果我传递 req 对象本身,我会收到以下错误:

“data”参数必须是字符串类型或 Buffer、TypedArray 或 DataView 的实例。

将“整个请求有效负载”传递给加密库的正确方法是什么?

4

1 回答 1

3

好的,所以在尝试了一些其他变体之后,我找到了解决方案。您必须JSON.stringify(req.body)作为要加密的消息传递。也许这对其他人有帮助。

    const hash = crypto.createHmac('sha256', secret)
      .update(JSON.stringify(req.body)) // <-- this is the needed message to encrypt
      .digest("base64");

特殊字符编码的导入更新

app.use(bodyParser.json())在我的快速设置中使用过。这不适用于具有特殊字符的请求正文(例如德语变音符号 ä、ö、ü)。相反,我将不得不像这样设置正文解析器:

app.use(bodyParser.json({
  verify: (req, res, buf) => {
    req.rawBody = buf
  }
}))

然后,在加密而不是传递JSON.stringify(req.body)它必须是req.rawBody. 所以加密库的最终代码如下所示:

    const secret = keys.todoistClientSecret
    const hash = crypto.createHmac('sha256', secret)
      .update(req.rawBody)
      .digest("base64");

于 2020-06-01T14:13:31.697 回答