Node JS Javascript 中 HttpServerUtility.UrlTokenEncode 的匹配输出

Matching ouput for HttpServerUtility.UrlTokenEncode in NodeJS Javascript

我正在查看 dotnet 中的示例,如下所示:https://dotnetfiddle.net/t0y8yD

HttpServerUtility.UrlTokenEncode 方法的输出是:

Pn55YBwEH2S2BEM5qlNrq-LMNE8BDdHYwbWKFEHiPZo1

当我尝试在 NodeJS 中使用 encodeURIencodeURIComponent 或任何其他尝试完成相同的操作时,我得到以下信息:

Pn55YBwEH2S2BEM5qlNrq+LMNE8BDdHYwbWKFEHiPZo=

从上面可以看出'-'应该是'+'并且最后一个字符部分不同。哈希创建相同并输出相同的缓冲区。

  var hmac = crypto.createHmac("sha256", buf);
  hmac.update("9644873");
  var hash = hmac.digest("base64");

如何让两者匹配?另一个重要注意事项是,这是一个用例,我不确定是否有其他字符执行相同的操作。

我不确定是 dotnet 变体不正确还是 NodeJS 版本不正确。但是,比较将在 dotnet 端完成,所以我需要节点来匹配它。

两个结果的差异是由于node.js中使用了Base64URL encoding in the C# code vs. Base64编码造成的。

Base64URLBase64几乎相同,但是Base64编码使用字符+/=,它们有URL 中的特殊含义,因此必须避免。在 Base64URL 编码中,+ 被替换为 -/ 被替换为 _=(末尾的填充字符)被替换为%20 或干脆省略。

在您的代码中,您正在计算 HMAC-SHA256 哈希值,因此您会得到一个 256 位的结果,可以用 32 个字节进行编码。在 Base64/Base64URL 中,每个字符代表 6 位,因此您需要 256/6 = 42,66 => 43 个 Base64 字符。对于 43 个字符,您将在末尾有 2 'lonesome' 位,因此添加了一个填充字符 (=)。 现在的问题是为什么 HttpServerUtility.UrlTokenEncode 添加一个 1 作为末尾填充字符的替代品。我在 documentation 中没有找到任何内容。但是你要记住,反正都是微不足道的。

要在 node.js 中获得相同的结果,您可以使用包 base64url,或者只在 base64 编码哈希上使用简单的 replace 语句。

使用 base64url 包:

const base64url = require('base64url');
var hmacB64 = "Pn55YBwEH2S2BEM5qlNrq+LMNE8BDdHYwbWKFEHiPZo="
var hmacB64url = base64url.fromBase64(hmacb64)

console.log(hmacB64url)

结果是:

Pn55YBwEH2S2BEM5qlNrq-LMNE8BDdHYwbWKFEHiPZo

如您所见,这个库只是省略了填充字符。

With replace,也将填充 = 替换为 1:

var hmacB64 = "Pn55YBwEH2S2BEM5qlNrq+LMNE8BDdHYwbWKFEHiPZo="
console.log(hmacb64.replace(/\//g,'_').replace(/\+/g,'-').replace(/\=+$/m,'1'))

结果是:

Pn55YBwEH2S2BEM5qlNrq-LMNE8BDdHYwbWKFEHiPZo1

我用不同的数据尝试了 C# 代码,最后总是得到'1',所以用 1 替换 = 似乎没问题,虽然它似乎不是符合RFC。

另一种选择(如果这适合您)是更改 C# 代码。使用正常的 base64 编码加上字符串替换来获得 base64url 输出而不是使用 HttpServerUtility.UrlTokenEncode

描述了一个可能的解决方案 here

我是新来的,所以我不能发表评论(需要 50 声望),但我想在@jqs 的回答中补充一点,如果字符串以两个“=”结尾,则替换需要用“2”。所以我的替换看起来像:

hmacb64.replace(///g,'_').replace(/+/g,'-').replace(/\=\=$/m,'2').replace (/\=$/m,'1')