【问题标题】:Comparing NodeJS buffers while avoiding timing attacks在避免定时攻击的同时比较 NodeJS 缓冲区
【发布时间】:2013-10-04 22:18:19
【问题描述】:

我正在使用 NodeJS 编写一个应用程序,它使用两个 Base64 编码的令牌来验证用户身份。这两个标记在异或时应该与存储在数据库中的第三个标记匹配。

这就是我现在拥有的:

function verifyTokens(encodedTokens) {
    var similarity = 0;
    var buffers = encodedTokens.map(base64.decode);
    for (i = 0; i < TOKEN_LENGTH; i++) {
        if ((buffers[0][i] ^ buffers[1][i]) === buffers[2][i]) {
            similarity += 1;
        }
    }
    return (similarity === TOKEN_LENGTH);
}

我认为这对计时攻击是不安全的,因为将 1 添加到 similarity 可能比什么都不做要花费更多的时间。我也不知道 JavaScript 相等运算符有多安全。

另一个引起我注意的使用缓冲区的解决方案是node-buffertools,但它使用memcmp 来比较缓冲区(我知道这不安全)。

比较两个 XORed 缓冲区与避免计时攻击的第三个缓冲区的最佳方法是什么?与 C++ 扩展相比,我更喜欢纯 JavaScript 解决方案。

【问题讨论】:

  • 不知道“比较两个 XORed 缓冲区的最佳方法”的答案,但您可以在返回之前花费额外的时间。这不可行吗?
  • 是的,我还计划延迟身份验证响应。我不确定它本身是否足以应对定时攻击,即使延迟是随机的。
  • 是的,我想进行一些测试以了解 XOR 操作需要多长时间,并添加一个 setTimeout 包装器以确保函数在较长时间后返回(在这两种情况下)
  • 另外,除了问题,它是什么认证方法?带有规格的链接可能有用(这将是出于我个人的好奇心/利益)

标签: javascript node.js security timing


【解决方案1】:

您可以添加结果布尔值:

function verifyTokens(encodedTokens) {
    var buffers = encodedTokens.map(base64.decode);
    var similarity = 0;

    for (var i = 0; i < TOKEN_LENGTH; i++) {
        similarity += (buffers[0][i] ^ buffers[1][i]) === buffers[2][i]);
    }

    return similarity === TOKEN_LENGTH;
}

尽管 V8 可能会对此进行优化并扭曲结果。你可以自己测试一下。我会先测试encodedTokens.map(base64.decode)

【讨论】:

  • 这对我来说似乎是一个很好的改进。我应该如何进行定时攻击向量的测试?一个简单的重复基准测试是否足够准确,还是阅读源代码是唯一彻底的选择?
  • @molf:使用基准测试。来源可能不会有太大帮助。
【解决方案2】:
function verifyTokens(encodedTokens) {
    var similarity = 0;
    var buffers = encodedTokens.map(base64.decode);
    for (i = 0; i < TOKEN_LENGTH; i++) {
        similarity |= (buffers[0][i] ^ buffers[1][i]) | (buffers[1][i] ^ buffers[2][i]);
    }
    return similarity === 0;
}

可能同样的事情,但人们通常don't trust比较运算符。

【讨论】:

    【解决方案3】:

    您能否对所有三个标记进行异或并与零进行比较?

    var zeroes = new Buffer(Array(32)); // zero fills, not sure encoding
    function verifyTokens(encodedTokens) {
      var buffers = encodedTokens.map(base64.decode);
      var xor1 = buffers[0] ^ buffers[1];
      var xor2 = xor1 ^ buffers[2];
      if(xor2.toString() === zeroes.toString()){
        // there may be a better comparison operator
        // buf1 === buf2 seems to always return false with different encodings
        return true;
      } else {
        return false;
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-12
      • 2020-02-14
      • 2021-12-04
      • 2019-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-14
      相关资源
      最近更新 更多