我正在使用Classic ASP构建一个Facebook Page应用程序。我一直无法匹配Facebook作为POST signed_request
的第一部分传递给应用程序的签名。
由于VBScript中的密码学库很少,因此我使用的是服务器端Javascript和https://code.google.com/archive/p/crypto-js/中的crypto-js库
我已经尝试将Facebook https://developers.facebook.com/docs/games/gamesonfacebook/login#parsingsr上的文档中的PHP代码示例转换为Javascript。我可以生成signed_request
有效载荷的HMAC SHA256哈希,但是与signed_request
签名不匹配。
我认为问题在于Facebook的签名格式不同。它看起来是二进制(〜1抚慰..... ),而我正在生成的HMAC SHA256哈希是十六进制字符串( 7f7e8f5f ..... >)。在Facebook的PHP示例中,hash_hmac
函数使用原始二进制参数。因此,我认为我需要将Facebook的签名转换为十六进制,或者将我的签名转换为二进制,以便进行“苹果到苹果”比较并获得匹配。
这是我的代码:
/* Use the libraries from https://code.google.com/archive/p/crypto-js/
crypto-js/crypto-js.min.js
crypto-js/hmac-sha256.min.js
crypto-js/enc-base64.min.js
*/
var signedRequest = Request.queryString("signed_request")
var FB_APP_SECRET = "459f038.....";
var arSR = signedRequest.split(".");
var encodedSig = arSR[0];
var encodedPayload = arSR[1];
var payload = base64UrlDecode(encodedPayload);
var sig = base64UrlDecode(encodedSig);
var expectedSig;
expectedSig = CryptoJS.HmacSHA256(encodedPayload, FB_APP_SECRET); // Unaltered payload string; no match
expectedSig = CryptoJS.HmacSHA256(payload, FB_APP_SECRET); // base64-decoded payload string; no match
if (sig == expectedSig) {
Response.write(payload);
} else {
Response.write("Bad signature");
}
function base64UrlDecode(input) {
// Replace characters and convert from base64.
return Base64.decode(input.replace("-", "+").replace("_", "/"));
}
答案 0 :(得分:0)
研究了有关编码的crypto-js文档之后,我找到了解决方案。 https://code.google.com/archive/p/crypto-js/底部的“编码器”下列出了crypto-js提供的解编码方法(感谢微调,CBroe。)
解决方案是在签名上使用.toString()
。似乎crypto-js使用阻止比较匹配的单词格式。我也转而使用crypto-js提供的base64解码,以便坚持使用一个库。
这是我更新的代码:
/* Use the libraries from https://code.google.com/archive/p/crypto-js/
crypto-js/crypto-js.min.js
crypto-js/hmac-sha256.min.js
crypto-js/enc-base64.min.js
*/
var signedRequest = Request.queryString("signed_request")
var FB_APP_SECRET = "459f038.....";
var arSR = signedRequest.split(".");
var encodedSig = arSR[0];
var encodedPayload = arSR[1];
var payload = base64UrlDecode(encodedPayload);
var sig = base64UrlDecode(encodedSig);
var expectedSig = CryptoJS.HmacSHA256(encodedPayload, FB_APP_SECRET); /******** Correct payload */
if (sig.toString() != expectedSig.toString()) { /******* Use .toString() to convert to normal strings */
Response.write(payload);
} else {
Response.write("Bad signature");
}
function base64UrlDecode(input) {
return CryptoJS.enc.Base64.parse( /******** Decode */
input.replace("-", "+").replace("_", "/") // Replace characters
);
}
答案 1 :(得分:0)
我最近针对其所需的用户数据删除网络挂钩实现了此功能。不再需要外部依赖项:
const crypto = require('crypto');
function parseSignedRequest(signedRequest, secret) {
const [signatureReceived, encodedPayload] = signedRequest.split('.', 2);
const payload = b64decode(encodedPayload)
const data = JSON.parse(payload);
const hmac = crypto.createHmac('sha256', secret).update(payload);
const expectedSignature = hmac.digest('base64');
if (signatureReceived === expectedSignature) {
return data;
} else {
throw new Error("Signature mismatch");
}
}
function b64decode(data) {
const buff = Buffer.from(data, 'base64');
return buff.toString('ascii');
}
这是their example PHP code的翻译。我也有a repo setup的测试。