在javascript中生成具有要求的随机密码字符串

IT技术 javascript random
2021-03-11 11:14:41

我想生成一个随机字符串,它必须有 az 中的 5 个字母和 3 个数字。

我怎样才能用 JavaScript 做到这一点?

我有以下脚本,但它不符合我的要求。

        var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        var string_length = 8;
        var randomstring = '';
        for (var i=0; i<string_length; i++) {
            var rnum = Math.floor(Math.random() * chars.length);
            randomstring += chars.substring(rnum,rnum+1);
        }
6个回答

强制固定数量的字符是一个主意。它不会提高密码的质量。更糟糕的是,它减少了可能的密码数量,因此通过暴力破解的黑客攻击变得更加容易。

要生成由字母数字字符组成的随机单词,请使用:

var randomstring = Math.random().toString(36).slice(-8);

它是如何工作的?

Math.random()                        // Generate random number, eg: 0.123456
             .toString(36)           // Convert  to base-36 : "0.4fzyo82mvyr"
                          .slice(-8);// Cut off last 8 characters : "yo82mvyr"

Number.prototype.toStringstring.prototype.slice方法的文档

不要使用这个:由于数字从二进制转换为十进制,并且没有足够的位来“填充”完整的十进制空间,最后一位数字将仅从一组特定的值中选择。例如,在我的电脑上,最后一位数字只有“i”、“r”和“9”。改用这个:Math.random().toString(36).substr(2, 8)
2021-04-21 11:14:41
解释 36 的作用: 来自mozilla 的 toString() 方法解析它的第一个参数,并尝试以指定的基数(基数)返回字符串表示。对于大于 10 的基数,字母表中的字母表示大于 9 的数字。例如,对于十六进制数(基数为 16),使用 a 到 f。所以据此,使用基数36,我们在0-9之后得到az。
2021-04-28 11:14:41
没有看到这如何解决 OP 要求“来自 az 的 5 个字母和 3 个数字”我明白了,作者认为这是一个坏主意......但它仍然是要求
2021-05-01 11:14:41
@ShishirGupta.toString只接受最多 36 的基数。这个答案是作为非加密随机字符串的单行。如果您还想使用大写字母,请使用Math.random(或crypto.getRandomValues如果可用)并将结果映射到 az, AZ, 0-9。例如使用下面的 saaj 答案。
2021-05-06 11:14:41
我同意,但有时你不能决定;)
2021-05-13 11:14:41

一种更易于维护和安全的方法。

更新以扩展我的意思及其工作原理。

  1. 安全MDN 非常明确地使用Math.random for 任何与安全相关的内容

    Math.random() 提供加密安全的随机数。不要将它们用于与安全相关的任何事情。改用 Web Crypto API,更准确地说是该window.crypto.getRandomValues()方法。

    看看2020 年的 can-i-use,getRandomValues您可能不再需要msCryptoMath.randomfallback ,除非您关心古老的浏览器。

  2. 可维护主要是RegExp _pattern作为一种简单的方法来定义您允许在密码中使用的字符类。但还有关于每个人的工作的 3 件事:定义一个模式,尽可能安全地获取随机字节,提供一个公共 API 将两者结合起来。

var Password = {
 
  _pattern : /[a-zA-Z0-9_\-\+\.]/,
  
  
  _getRandomByte : function()
  {
    // http://caniuse.com/#feat=getrandomvalues
    if(window.crypto && window.crypto.getRandomValues) 
    {
      var result = new Uint8Array(1);
      window.crypto.getRandomValues(result);
      return result[0];
    }
    else if(window.msCrypto && window.msCrypto.getRandomValues) 
    {
      var result = new Uint8Array(1);
      window.msCrypto.getRandomValues(result);
      return result[0];
    }
    else
    {
      return Math.floor(Math.random() * 256);
    }
  },
  
  generate : function(length)
  {
    return Array.apply(null, {'length': length})
      .map(function()
      {
        var result;
        while(true) 
        {
          result = String.fromCharCode(this._getRandomByte());
          if(this._pattern.test(result))
          {
            return result;
          }
        }        
      }, this)
      .join('');  
  }    
    
};
<input type='text' id='p'/><br/>
<input type='button' value ='generate' onclick='document.getElementById("p").value = Password.generate(16)'>

找到了一个支持 window.crypto.getRandomValues 并在 node.js 中工作的库github.com/bermi/password-generator
2021-04-24 11:14:41
只是想说我需要一些东西来在紧要关头生成密码,这很完美。谢谢!
2021-04-24 11:14:41
似乎每个回答的人都随机生成了一个密码,哈哈。如果调整 abit 实际上可以更匹配问题,则您的非常接近,更改_pattern_charset并实际上添加_pattern匹配以确定条件playcode.io/774196
2021-05-02 11:14:41
此外,这并不总是向生成的代码添加一个数字,并且 OP 需要最少 3。
2021-05-09 11:14:41

许多答案(包括这个答案的原件)都没有解决 OP 的字母和数字计数要求。以下是两种解决方案:通用(无最小字母/数字)和规则。

一般的:

我相信这是比上面更好的通用解决方案,因为:

  • 它比接受/最高投票的答案更安全,也更通用,因为它以区分大小写的方式支持任何字符集
  • 它比其他答案更简洁(对于一般解决方案,最多 3 行;可以是单行)
  • 它仅使用本机 Javascript-无需安装或其他库

注意

  • 这对IE浏览器,在Array.fill()原型必须polyfilled
  • 如果可用,最好使用 window.crypto.getRandomValues() 而不是 Math.random() (感谢 @BenjaminH 指出)

三线:

var pwdChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
var pwdLen = 10;
var randPassword = Array(pwdLen).fill(pwdChars).map(function(x) { return x[Math.floor(Math.random() * x.length)] }).join('');

或者,作为单线:

var randPassword = Array(10).fill("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz").map(function(x) { return x[Math.floor(Math.random() * x.length)] }).join('');

使用字母/数字规则

现在,上述的变化。这将从给定的字符集(字母、数字或任一)生成三个随机字符串,然后对结果进行打乱。

请注意,以下使用 sort() 仅用于说明目的。对于生产用途,请将以下 sort() 函数替换为诸如Durstenfeld 之随机播放函数

首先,作为一个函数:

function randPassword(letters, numbers, either) {
  var chars = [
   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", // letters
   "0123456789", // numbers
   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" // either
  ];

  return [letters, numbers, either].map(function(len, i) {
    return Array(len).fill(chars[i]).map(function(x) {
      return x[Math.floor(Math.random() * x.length)];
    }).join('');
  }).concat().join('').split('').sort(function(){
    return 0.5-Math.random();
  }).join('')
}

// invoke like so: randPassword(5,3,2);

同样的事情,作为一个 2-liner(诚然,非常长和丑陋的线条——如果你使用适当的 shuffle 函数,它不会是一个 1-liner。不推荐,但有时它仍然很有趣):

var chars = ["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz","0123456789", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"];
var randPwd = [5,3,2].map(function(len, i) { return Array(len).fill(chars[i]).map(function(x) { return x[Math.floor(Math.random() * x.length)] }).join('') }).concat().join('').split('').sort(function(){return 0.5-Math.random()}).join('');
很好的答案,但大写字母 Y 永远不会出现在您生成的任何密码中。
2021-04-24 11:14:41
Math.random() 的使用也是可以预测的。因此,为了生成密码,最好使用像 window.crypto.getRandomValues 这样的函数。
2021-04-27 11:14:41
它更安全的原因是它支持输出中可能的字符数比使用 toString(36) 多。使用固定的输出长度(例如 8 个),如果您最多有 36 个字符可供选择,那么您的排列比有 62 个字符(如示例中)或更好的是,整个 95 个可打印字符(ascii ) 字符,或者如果使用 unicode,每个字节的可能性甚至更高。
2021-05-07 11:14:41
谢谢。我在 OP 问题中使用了字符集,但看起来它有缺陷。现已更新。
2021-05-11 11:14:41
你说“它比接受/最高投票的答案更安全”。你能详细说明原因吗?
2021-05-11 11:14:41

对于正在寻找最简单脚本的人。while (true),不if/else,没有声明。

基于 mwag 的答案,但这个使用crypto.getRandomValues,比 更强的随机数Math.random

var generatePassword = (
  length = 20,
  wishlist = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~!@-#$'
) =>
  Array.from(crypto.getRandomValues(new Uint32Array(length)))
    .map((x) => wishlist[x % wishlist.length])
    .join('')

console.log(generatePassword())

小书签

javascript:prompt("Random password:",((o=20,n="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~!@-#$")=>Array.from(crypto.getRandomValues(new Uint32Array(o))).map(o=>n[o%n.length]).join(""))())

节点.js

const crypto = require('crypto')

const generatePassword = (
  length = 20,
  wishlist = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~!@-#$'
) =>
  Array.from(crypto.randomFillSync(new Uint32Array(length)))
    .map((x) => wishlist[x % wishlist.length])
    .join('')

console.log(generatePassword())

Python

#!/usr/bin/env python

import os


def rand(length: int) -> str:
    bytes = os.urandom(length)
    chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-"
    cl = len(chars)
    rs = ''
    for i in bytes:
        rs += chars[i % cl]
    return rs


print(rand(18))

参见:https : //stackoverflow.com/a/67035900/1099314

添加了 Node.js 版本。谢谢@Rvy Pandey。
2021-04-24 11:14:41
好收获@bryc。更新。谢谢。
2021-05-07 11:14:41
由于未定义的偏移量,这不会始终提供 20 个长度的密码。+ 1部件不是必需的,可以移除。
2021-05-13 11:14:41
有用且简单的解决方案。任何希望在NodeJS 中执行此操作的人都可以简单地替换crypto.getRandomValuescrypto.randomFillSync
2021-05-20 11:14:41

正如@RobW 指出的那样,将密码限制为 OP 方案中提出的固定数量的字符是一个坏主意但更糟糕的是,提出基于代码的答案是Math.random一个非常糟糕的主意

让我们从坏主意开始OP 代码从一组 62 个字符中随机选择一个包含 8 个字符的字符串。将随机字符串限制为 5 个字母和 3 个数字意味着生成的密码最多将具有28.5 位的熵(与潜在的 47.6 位相反)如果取消了 5 个字母和 3 个数字的分配限制)。那不太好。但实际上,情况更糟。所述充其量代码的方面是通过使用破坏Math.random作为密码产生熵的手段。Math.random是一个伪随机数生成器由于伪随机数生成器的确定性,生成的密码的熵非常糟糕,使任何此类提议的解决方案都成为一个非常糟糕的主意假设这些密码被分发给最终用户(o/w 有什么意义),收到这样的密码的活跃对手很有可能预测未来分发给其他用户的密码,这可能不是一件好事。

但回到刚才的坏主意假设使用密码强的伪随机数生成器而不是Math.random为什么要将密码限制为 28.5 位?如前所述,这不是很好。想必5个字母3个数字的方案是为了帮助用户管理随机分发的密码。但是让我们面对它,你必须平衡易用性使用的value和熵的28.5位不是针对主动攻击防御多少value。

但坏事已经够多了。让我们提出一条前进的道路。我将使用 JavaScript EntropyString库,它“从各种字符集高效地生成具有指定熵的加密强随机字符串”。我将使用选择 32 个字符的字符集,而不是 OP 62 个字符,以减少使用容易混淆的字符或形成英文单词。而不是 5 个字母、3 个数字方案(它的熵太少),我将宣布密码将具有 60 位的熵(这是易用性与value的平衡)。

import { Entropy, charSet32 } from 'entropy-string'
const random = new Entropy({ bits: 60, charset: charset32 })
const string = random.string()

“Q7LfR8Jn7RDp”

请注意Entropy指定所需熵位的参数,而不是更常见的随机字符串生成解决方案,该解决方案指定传入字符串长度(这既被误导又通常未指定,但这是另一回事)。

代码片段已更新为库的较新版本。库 README 和 GitHub 存储库中也有很多示例。
2021-05-11 11:14:41
谢谢!请注意,此处的示例不再有效。
2021-05-14 11:14:41