私は Play フレームワーク (この場合は 2.5 と Scala) の初心者ですが、Facebook メッセンジャー用のボットを作成して学習しようとしています。ただし、メッセージの署名を検証しようとして行き詰まりました。
Facebook のドキュメントに従って、Webhook を作成しました。を使用して POST リクエストを処理しますgetRawMessages
(以下のコードを参照)。次に、この関数を使用して、要求が 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 要求には、アプリ シークレットをキーとして使用し、sha1= というプレフィックスを付けて、要求ペイロードの SHA1 署名を含む X-Hub-Signature ヘッダーが含まれます。コールバック エンドポイントは、この署名を検証して、ペイロードの整合性と発信元を検証できます。
計算は、ペイロードのエスケープされた Unicode バージョンで行われ、小文字の 16 進数で行われることに注意してください。デコードされたバイトに対して計算するだけでは、別の署名になってしまいます。たとえば、文字列 äöå は \u00e4\u00f6\u00e5 にエスケープする必要があります。
私が見逃しているのは、ペイロードを適切にユニコードにエスケープすることだと思いますが、それを行う方法が見つからないようです。また、参照されている質問の回答も、何もせずにバイト配列を取得するように見えました ( jsonRawBytes = jsonRaw.asBytes();
)。
続行する方法についての助けをいただければ幸いです。