Facebook 小游戏玩家签名验证失败
Facebook instant game player signature verification fails
我目前正在 Facebook 上开发一款即时游戏,需要验证来自 Facebook 的玩家信息是否真实。 Facebook 通过此处记录的散列签名提供验证:
https://developers.facebook.com/docs/games/instant-games/sdk/fbinstant6.2#signedplayerinfo
我按照概述的步骤进行操作,但始终无法获得匹配的签名:
这是签名:
$_POST['psig'] = 'je3yV8uKmysDrjXv1xp_RY2rTMJLEREM7xj8SGt5HEk.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImlzc3VlZF9hdCI6MTU1MjI1NTc2OCwicGxheWVyX2lkIjoiMjA1OTE4OTA2MDgyMzk4MyIsInJlcXVlc3RfcGF5bG9hZCI6InBkYXRhIn0';
1) 将签名分成由“.”分隔的两部分字符.
$first_part = explode('.', $_POST['psig'])[0];
echo $first_part;
// Output:
je3yV8uKmysDrjXv1xp_RY2rTMJLEREM7xj8SGt5HEk
$second_part = explode('.', $_POST['psig'])[1];
echo $second_part;
// Output
eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImlzc3VlZF9hdCI6MTU1MjI1NTc2OCwicGxheWVyX2lkIjoiMjA1OTE4OTA2MDgyMzk4MyIsInJlcXVlc3RfcGF5bG9hZCI6InBkYXRhIn0
2) 用base64url编码解码第一部分(编码后的签名)
echo base64_decode($first_part);
// Output:
���Wˊ�+�5��Qcj�0��DC;�?�G
3) 使用 base64url 编码解码第二部分(响应负载),它应该是 JSON 对象的字符串表示形式,具有以下字段:** algorithm - 始终等于 HMAC-SHA256 ** issued_at - 发出此响应时的 unix 时间戳。 ** player_id - 玩家的唯一标识符。 ** request_payload - 您在调用 FBInstant.player.getSignedPlayerInfoAsync.
时指定的 requestPayload 字符串
$payload = base64_decode($second_part);
echo $payload;
// Output:
{"algorithm":"HMAC-SHA256","issued_at":1552255768,"player_id":"2059189060823983","request_payload":"pdata"}
4) 使用 HMAC SHA-256 和您的应用密码对整个响应有效负载字符串进行哈希处理,并确认它等于编码签名。
$check = hash_hmac('sha256', $payload, 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', true);
echo $check;
// Output:
n4Q�Kމ`<�?�����tT�~x����L�
我花了几个小时来解决这个问题,但我不知道我做错了什么!
终于明白了!
我有 2 个错误:
1) 在解码要检查的编码签名时,应使用 base64decode URL 而不是常规的 base64decode。所以第2步的代码应该是这样的:
$first_part = base64_decode(str_replace(array('-', '_'), array('+', '/'), $first_part));
2) 生成的哈希值应该是原始编码的 response payload
字符串,而不是解码后的字符串。该文档对此不是很清楚。所以应该是这样的:
$check = hash_hmac('sha256', $second_part, $app_secret, true);
通过上述操作,解码后的签名将等于生成的哈希中的二进制数据:)
最后检查签名是否有效:
if($first_part == $check){
//valid
}
我目前正在 Facebook 上开发一款即时游戏,需要验证来自 Facebook 的玩家信息是否真实。 Facebook 通过此处记录的散列签名提供验证:
https://developers.facebook.com/docs/games/instant-games/sdk/fbinstant6.2#signedplayerinfo
我按照概述的步骤进行操作,但始终无法获得匹配的签名:
这是签名:
$_POST['psig'] = 'je3yV8uKmysDrjXv1xp_RY2rTMJLEREM7xj8SGt5HEk.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImlzc3VlZF9hdCI6MTU1MjI1NTc2OCwicGxheWVyX2lkIjoiMjA1OTE4OTA2MDgyMzk4MyIsInJlcXVlc3RfcGF5bG9hZCI6InBkYXRhIn0';
1) 将签名分成由“.”分隔的两部分字符.
$first_part = explode('.', $_POST['psig'])[0];
echo $first_part;
// Output:
je3yV8uKmysDrjXv1xp_RY2rTMJLEREM7xj8SGt5HEk
$second_part = explode('.', $_POST['psig'])[1];
echo $second_part;
// Output
eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImlzc3VlZF9hdCI6MTU1MjI1NTc2OCwicGxheWVyX2lkIjoiMjA1OTE4OTA2MDgyMzk4MyIsInJlcXVlc3RfcGF5bG9hZCI6InBkYXRhIn0
2) 用base64url编码解码第一部分(编码后的签名)
echo base64_decode($first_part);
// Output:
���Wˊ�+�5��Qcj�0��DC;�?�G
3) 使用 base64url 编码解码第二部分(响应负载),它应该是 JSON 对象的字符串表示形式,具有以下字段:** algorithm - 始终等于 HMAC-SHA256 ** issued_at - 发出此响应时的 unix 时间戳。 ** player_id - 玩家的唯一标识符。 ** request_payload - 您在调用 FBInstant.player.getSignedPlayerInfoAsync.
时指定的 requestPayload 字符串$payload = base64_decode($second_part);
echo $payload;
// Output:
{"algorithm":"HMAC-SHA256","issued_at":1552255768,"player_id":"2059189060823983","request_payload":"pdata"}
4) 使用 HMAC SHA-256 和您的应用密码对整个响应有效负载字符串进行哈希处理,并确认它等于编码签名。
$check = hash_hmac('sha256', $payload, 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', true);
echo $check;
// Output:
n4Q�Kމ`<�?�����tT�~x����L�
我花了几个小时来解决这个问题,但我不知道我做错了什么!
终于明白了!
我有 2 个错误:
1) 在解码要检查的编码签名时,应使用 base64decode URL 而不是常规的 base64decode。所以第2步的代码应该是这样的:
$first_part = base64_decode(str_replace(array('-', '_'), array('+', '/'), $first_part));
2) 生成的哈希值应该是原始编码的 response payload
字符串,而不是解码后的字符串。该文档对此不是很清楚。所以应该是这样的:
$check = hash_hmac('sha256', $second_part, $app_secret, true);
通过上述操作,解码后的签名将等于生成的哈希中的二进制数据:)
最后检查签名是否有效:
if($first_part == $check){
//valid
}