【问题标题】:Is this is a good way to generate a secure random string in JavaScript?这是在 JavaScript 中生成安全随机字符串的好方法吗?
【发布时间】:2014-06-08 14:41:45
【问题描述】:

以下是我编写的一些代码,用于在 JavaScript 中生成随机字符串。如果我将从此方法接收的值用作用户的盐或令牌,是否存在任何安全问题?

String.random = function(length, characters) {
    length = length === undefined ? 32 : length;
    characters = characters === undefined ? 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' : characters;

    var maxIndex = characters.length - 1;
    var string = '';

    for(var i = 0; i < length; i++) {
        string += characters[Number.random(0, maxIndex)];
    }

    return string;
}

【问题讨论】:

  • 这个问题似乎离题了,因为它可能更适合security.stackexchange.com
  • 有这么多堆栈交换让我感到难过。
  • @g.d.d.c 虽然 security.stackexchange.com 看起来更适合这个问题,但我不确定他们是否有知识来回答这个问题。基本点是:有没有其他方法可以在 Javascript 中生成随机数?不是那么微不足道。
  • 如果您不想自己进行加密,我建议您查看一些 bcrypt/blowfish 库。不知道任何 js 寿 ;(
  • 我向Javascript to generate random password with specific number of letters推荐我的答案。它使用浏览器内置的安全 PRNG。

标签: javascript string random cryptography


【解决方案1】:

您可以使用crypto.getRandomValues() 在 javascript 中获取密码安全的随机数,但它们不是像 Math.random() 这样的十进制数,因此需要更多的工作来处理它们。这是带有 crypto.getRandomValues() 的普通 javascipt 解决方案:

function getCryptoRandomBetween(min, max){
  //the highest random value that crypto.getRandomValues could store in a Uint32Array
  var MAX_VAL = 4294967295;
  
  //find the number of randoms we'll need to generate in order to give every number between min and max a fair chance
  var numberOfRandomsNeeded = Math.ceil((max - min) / MAX_VAL);
  
  //grab those randoms
  var cryptoRandomNumbers = new Uint32Array(numberOfRandomsNeeded);
  crypto.getRandomValues(cryptoRandomNumbers);
  
  //add them together
  for(var i = 0, sum = 0; i < cryptoRandomNumbers.length; i++){
    sum += cryptoRandomNumbers[i];
  }
  
  //and divide their sum by the max possible value to get a decimal
  var randomDecimal = sum / (MAX_VAL * numberOfRandomsNeeded);
  
  //if result is 1, retry. otherwise, return decimal.
  return randomDecimal === 1 ? getCryptoRandomBetween(min, max) : Math.floor(randomDecimal * (max - min + 1) + min);
}

function getRandomChar(str){
  return str.charAt(getCryptoRandomBetween(0, str.length - 1));
}

String.random = function(length, characters) {
  for(var i = 0, str = ""; i < length; i++) str += getRandomChar(characters);
  return str;
};

console.log(String.random(60, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"));

眼睛很粗糙,但它有效。如果您想要一个更简单的解决方案,我的首选是rando.js。它适用于纯 javascript 以及 Node.js/React。您可以使用rando(str) 从字符串中获取随机字符,因此按照您想要的方式构建随机字符串非常简单:

String.random = function(length, characters) {
  for(var i = 0, str = ""; i < length; i++) str += rando(characters);
  return str;
};

console.log(String.random(60, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"));
&lt;script src="https://randojs.com/2.0.0.js"&gt;&lt;/script&gt;

让我重申一下,这两种解决方案生成的字符串都具有足够的熵,可以安全地用作用户的密码、盐或令牌。

【讨论】:

    【解决方案2】:

    我认为这一切都归结为找到一种在 Javascript 中生成随机数的替代方法,而不是依赖于 Math.random

    一旦您有了Math.random 的替代品,您就可以以几乎相同的方式生成随机字符串。我建议看看Mersenne twister 算法。周围有很多 Javascript 实现(有些甚至在我链接的维基百科页面中)。

    与许多随机数生成器一样,您必须从种子开始:您可以使用 Math.random 生成一个,如果您愿意,可以添加一个额外的“盐”。

    【讨论】:

    • MT 不安全,由于Math.random 在大多数浏览器中不安全,因此使用它来生成种子不是一个好主意。
    • @CodesInChaos 谁谈到了浏览器?它可能是 NodeJS。无论如何,你应该使用crypto 发布答案,我其实不知道。
    • 如果您使用Math.random作为MT的种子,您的MT随机数序列将仅与Math.random一样安全。没有办法以计算方式生成安全性。 (即创建熵)因为它安全,所以不要将它用于任何与安全相关的事情。请改用window.crypto.getRandomValues()
    【解决方案3】:

    在 NodeJs 中使用加密库生成随机字符串

    import { randomBytes } from 'crypto';
    
    function random(length) {
        return randomBytes(Math.ceil(length / 2)).toString('hex').slice(0, length);
    }
    
    const randomString = random(10);
    

    【讨论】:

      【解决方案4】:

      使用crypto.getRandomValues,您可以轻松生成安全的随机标识符:

      function genId(){
        let array = new Uint8Array(16);
        crypto.getRandomValues(array);
        return btoa(array);
      }
      

      【讨论】:

        猜你喜欢
        • 2010-11-01
        • 2012-08-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-23
        • 1970-01-01
        • 1970-01-01
        • 2012-02-12
        相关资源
        最近更新 更多