在Javascript中验证Facebook签名请求签名
我正在用经典ASP构建一个Facebook页面应用程序。我无法匹配Facebook作为发布的在Javascript中验证Facebook签名请求签名,javascript,facebook,sha256,hmac,Javascript,Facebook,Sha256,Hmac,我正在用经典ASP构建一个Facebook页面应用程序。我无法匹配Facebook作为发布的signed\u请求的第一部分传递到应用程序中的签名 因为VBScript中很少有用于加密的库,所以我使用服务器端Javascript和来自的crypto js库 我已经尝试将Facebook的文档中的PHP代码示例翻译成Javascript。我可以生成signed\u请求有效负载的HMAC SHA256哈希,但与signed\u请求签名不匹配 我认为问题在于Facebook的签名格式不同。它看起来是二进
signed\u请求的第一部分传递到应用程序中的签名
因为VBScript中很少有用于加密的库,所以我使用服务器端Javascript和来自的crypto js库
我已经尝试将Facebook的文档中的PHP代码示例翻译成Javascript。我可以生成signed\u请求
有效负载的HMAC SHA256哈希,但与signed\u请求
签名不匹配
我认为问题在于Facebook的签名格式不同。它看起来是二进制的(~1.抚Ö…)而我生成的HMAC SHA256哈希是一个十六进制字符串(7f7e8f5f…)。在Facebook的PHP示例中,hash\uhmac
函数使用原始二进制参数。因此,我认为我需要将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("_", "/"));
}
在查阅了关于编码的crypto js文档后,我找到了解决方案。crypto js提供的反/编码方法列在的底部的“编码器”下(感谢您的轻推,CBroe)
解决方案是在签名上使用.toString()
。crypto js似乎使用了阻止比较匹配的word格式。为了坚持使用一个库,我也切换到使用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
);
}
我最近为他们所需的用户数据删除webhook实现了这个功能。不再需要外部依赖项:
const crypto=require('crypto');
函数parseSignedRequest(signedRequest,secret){
const[signatureReceived,encodedPayload]=signedRequest.split('.',2);
常量有效负载=B64解码(encodedPayload)
const data=JSON.parse(有效负载);
const hmac=crypto.createHmac('sha256',secret).update(有效载荷);
const expectedSignature=hmac.digest('base64');
if(signatureReceived==预期签名){
返回数据;
}否则{
抛出新错误(“签名不匹配”);
}
}
功能B64解码(数据){
const buff=Buffer.from(数据'base64');
返回buff.toString('ascii');
}
这是我的翻译。我也有测试。根据crypto.js文档,它有自己的base64解码方法-也许可以尝试使用这些方法,而不是base64.decode
?(完成-+替换后。)