【问题标题】:Matching ouput for HttpServerUtility.UrlTokenEncode in NodeJS JavascriptNode JS Javascript 中 HttpServerUtility.UrlTokenEncode 的匹配输出
【发布时间】:2023-03-25 00:12:01
【问题描述】:

我正在查看 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 来匹配它。

【问题讨论】:

    标签: javascript asp.net node.js base64 urlencode


    【解决方案1】:

    这两种结果的差异是由于在C#代码中使用Base64URL编码与在node.js中使用Base64编码造成的。

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

    在您的代码中,您正在计算 HMAC-SHA256 哈希,因此您会得到一个 256 位的结果,它可以被编码为 32 个字节。在Base64/Base64URL 中,每个字符代表 6 位,因此您需要 256/6 = 42,66 => 43 个 Base64 字符。如果有 43 个字符,最后会有 2 个“孤独”位,因此会添加一个填充字符 (=)。 现在的问题是为什么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
    

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

    使用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

    【讨论】:

    • 不幸的是,因为我们将调用一个 API 来比较这两个值,所以它们需要完全匹配。如果有 base64url 填充以添加数字 1(而不是当前省略的 =),有没有办法可以“喇叭”。
    • 我尝试了您的 dotnefiddle 代码并更改了数据,但最后总是得到 '1',因此将 '=' 替换为 '1' 似乎可以节省。
    • 谢谢@jps,我认为我会直接更换,现在我知道更多关于差异的信息。
    • 可能是目前最好的灵魂。
    【解决方案2】:

    我是新来的,所以无法发表评论(需要 50 声望),但我想在@jqs 中添加答案,如果字符串以两个“=”结尾,则替换需要使用“2 ”。所以我的替换看起来像:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-16
      • 2016-03-08
      • 1970-01-01
      • 1970-01-01
      • 2018-10-17
      • 1970-01-01
      • 1970-01-01
      • 2021-08-03
      相关资源
      最近更新 更多