如何在PHP中按Facebook要求转义Unicode字符生成Webhook签名?
如何在PHP中实现符合Facebook要求的Unicode转义以生成正确的Webhook签名?
Facebook的Webhook验证规则明确:
请注意,我们使用经过Unicode转义(十六进制小写)的负载生成签名。如果直接对解码后的字节计算,会得到不同的签名。例如,字符串äöå应转义为\u00e4\u00f6\u00e5。
你在编写单元测试时遇到的问题,核心是mb_convert_encoding无法实现Facebook要求的仅对非ASCII字符做\uXXXX格式的小写十六进制转义——它是对整个字符串做编码转换,不符合需求。
解决方案
PHP中可以通过json_encode的默认行为实现符合要求的转义:json_encode会自动将非ASCII字符转义为\uXXXX格式的小写十六进制值,完全匹配Facebook的规则。你需要调整单元测试代码,确保计算签名的负载是符合该转义规则的JSON字符串,同时保证请求体与签名计算的负载一致。
修改后的单元测试代码
// 单元测试代码 $content = file_get_contents(__DIR__.'/../Responses/whatsapp_webhook.json'); $content = trim($content); // 将原始JSON解码为数组,再重新编码为符合Facebook要求的转义格式 $payloadArray = json_decode($content, true); // 默认参数自动转义非ASCII为\uXXXX小写,同时保持斜杠不转义 $escapedPayload = json_encode($payloadArray, JSON_UNESCAPED_SLASHES); $secret = config('externals.meta.config.app_secret'); // 基于转义后的JSON字符串计算HMAC签名 $signature = hash_hmac( 'sha256', $escapedPayload, $secret ); // 发送请求时直接使用转义后的JSON字符串作为请求体,确保与签名计算的负载一致 $response = $this->post( route('whatsapp.webhook.message'), $escapedPayload, [ 'CONTENT_TYPE' => 'application/json', // Facebook签名格式为"sha256=签名值",需带上前缀 'X-Hub-Signature-256' => "sha256={$signature}", ] ); $response->assertOk();
关键注意事项
- 签名计算的负载必须与请求体一致:Facebook是基于发送给你的原始JSON字符串(已做Unicode转义)计算签名,测试时必须用相同转义规则的字符串计算签名,并作为请求体发送。
- 签名格式正确:
X-Hub-Signature-256的格式是sha256=签名值,不能省略前缀。 - 请求头Content-Type正确:Webhook请求的Content-Type应为
application/json,而非text/plain。
你的现有请求验证代码无需修改,因为$request->getContent()会直接获取Facebook发送的原始转义JSON字符串,与签名计算的负载匹配。
内容的提问来源于stack exchange,提问作者shamaseen
相关产品推荐
相关产品推荐

