从 Facebook 验证 X-Hub-Signature
Verify X-Hub-Signature from Facebook
我是 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 docs 状态:
The HTTP request will contain an X-Hub-Signature header which contains
the SHA1 signature of the request payload, using the app secret as the
key, and prefixed with sha1=. Your callback endpoint can verify this
signature to validate the integrity and origin of the payload
Please note that the calculation is made on the escaped unicode
version of the payload, with lower case hex digits. If you just
calculate against the decoded bytes, you will end up with a different
signature. For example, the string äöå should be escaped to
\u00e4\u00f6\u00e5.
我猜想我缺少的是将有效负载正确转义为 unicode,但我似乎无法找到一种方法来做到这一点。并且所引用问题中的答案似乎也只是获取了字节数组,而没有对其进行任何其他操作 (jsonRawBytes = jsonRaw.asBytes();
)。
任何关于如何进行的帮助将不胜感激。
原来我一直在使用错误的秘密。如果其他人犯了同样的错误,请注意它 "App Secret" 在您想要的应用程序仪表板上可用。请参阅下面的屏幕截图。
我是 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 docs 状态:
The HTTP request will contain an X-Hub-Signature header which contains the SHA1 signature of the request payload, using the app secret as the key, and prefixed with sha1=. Your callback endpoint can verify this signature to validate the integrity and origin of the payload
Please note that the calculation is made on the escaped unicode version of the payload, with lower case hex digits. If you just calculate against the decoded bytes, you will end up with a different signature. For example, the string äöå should be escaped to \u00e4\u00f6\u00e5.
我猜想我缺少的是将有效负载正确转义为 unicode,但我似乎无法找到一种方法来做到这一点。并且所引用问题中的答案似乎也只是获取了字节数组,而没有对其进行任何其他操作 (jsonRawBytes = jsonRaw.asBytes();
)。
任何关于如何进行的帮助将不胜感激。
原来我一直在使用错误的秘密。如果其他人犯了同样的错误,请注意它 "App Secret" 在您想要的应用程序仪表板上可用。请参阅下面的屏幕截图。