我是 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();
)。
任何有关如何进行的帮助将不胜感激。