6

我是 Play Framework(在本例中为 2.5 和 Scala)的初学者——我正在尝试通过为 Facebook Messenger 构建机器人来学习。但是,我在尝试验证消息的签名时遇到了困难。

我遵循了 Facebook 文档并创建了一个 webhook。getRawMessages它使用(参见下面的代码)处理 POST 请求。然后尝试验证请求是否由 Facebook 使用该verifyPayload函数签名。但是,我似乎无法使计算的哈希值和实际的哈希值匹配。

我已经率先研究了这个问题:How to verify Instagram real-time API x-hub-signature in Java?这似乎做了我想要的,但对于 Instagram 等价物。但我似乎仍然无法正确处理。

val secret = "<facebooks secret token>"  

def getRawMessages = Action (parse.raw) {
    request =>

      val xHubSignatureOption = request.headers.get("X-Hub-Signature")

      try {
        for {
          signature <- xHubSignatureOption
          rawBodyAsBytes <- request.body.asBytes()
        } yield {
          val rawBody = rawBodyAsBytes.toArray[Byte]
          val incomingHash = signature.split("=").last
          val verified = verifyPayload(rawBody, secret, incomingHash)
          Logger.info(s"Was verified? $verified")
        }
        Ok("Test")
      }
      catch {
        case _ => Ok("Test")
      }
  }

  val HMAC_SHA1_ALGORITHM = "HmacSHA1"

  def verifyPayload(payloadBytes: Array[Byte], secret: String, expected: String): Boolean =  {

    val secretKeySpec = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), HMAC_SHA1_ALGORITHM)
    val mac = Mac.getInstance(HMAC_SHA1_ALGORITHM)
    mac.init(secretKeySpec)
    val result = mac.doFinal(payloadBytes)

    val computedHash = Hex.encodeHex(result).mkString
    Logger.info(s"Computed hash: $computedHash")

    computedHash == expected
  }

Facebook webhook 文档状态:

HTTP 请求将包含一个 X-Hub-Signature 标头,其中包含请求有效负载的 SHA1 签名,使用应用程序密钥作为密钥,并以 sha1= 为前缀。您的回调端点可以验证此签名以验证有效负载的完整性和来源

请注意,计算是根据有效载荷的转义 unicode 版本进行的,使用小写十六进制数字。如果您只是针对解码的字节进行计算,您最终会得到不同的签名。例如,字符串 äöå 应转义为 \u00e4\u00f6\u00e5。

我猜我缺少的是让有效负载正确地转义为 unicode,但我似乎无法找到一种方法来做到这一点。引用问题中的答案似乎也只是得到了字节数组,而不用做更多的事情(jsonRawBytes = jsonRaw.asBytes();)。

任何有关如何进行的帮助将不胜感激。

4

1 回答 1

7

原来我一直在使用错误的秘密。如果其他人犯了同样的错误,请注意您想要的应用程序仪表板上提供的“应用程序秘密”。请参阅下面的屏幕截图。

在此处输入图像描述

于 2016-06-08T17:47:31.133 回答