在JavaScript中生成带有要求的随机密码字符串


94

我想生成一个随机字符串,该字符串必须具有来自z的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
如果满足您的要求,那又是什么问题?另外,您的强制密码要求不是一个好主意。
罗伯W


2
new Array(12).fill().map(() => String.fromCharCode(Math.random()*86+40)).join("") 十分之一的班轮以一种非常轻巧的方式生成一个12字符的密码,并带有特殊的字符上限和下限数字
Tofandel

Answers:


309

强制固定数量的字符是一个主意。它不会提高密码的质量。更糟糕的是,它减少了可能的密码数量,从而使暴力破解变得更加容易。

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

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方法的文档。


6
我同意,但有时您无法决定;)
ffffff01 2012年

38
不要使用此方法:由于数字是从二进制转换为十进制,并且没有足够的位“填充”整个十进制空间,因此只能从一组特定的值中选择最后一位。例如,在我的计算机上,最后一位仅是“ i”,“ r”和“ 9”。改用它:Math.random().toString(36).substr(2, 8)
Joel

1
解释36的作用:从mozilla中 ,toString()方法解析其第一个参数,并尝试返回指定基数(基数)的字符串表示形式。对于大于10的基数,字母表示大于9的数字。例如,对于十六进制数字(以16为底),使用a至f。因此,据此,使用基数36,我们在0-9之后得到az。
Shishir Gupta'6

2
@ShishirGupta .toString仅接受不超过36的基数。此答案是作为非加密随机字符串的单行代码。如果还希望有大写字母,请使用Math.random(或crypto.getRandomValues如果有)并将结果映射到az,AZ,0-9。例如,在下面使用saaj的答案。
罗布W

1
没有看到这如何满足OP要求“ az中的5个字母和3个数字”。我明白了,作者认为这是个坏主意……但这仍然是要求
mwag

38

更具可维护性和安全性的方法。

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)'>


此外,这并不总是在生成的代码中增加一个数字,OP至少需要
3。– qwertzman

找到了一个支持window.crypto.getRandomValues的库,并且可以在node.js中工作。github.com/bermi/password
Eugene,

只是想说我需要一些紧急情况来生成密码,这很完美。谢谢!
凯尔(Kyle K)

29

许多答案(包括该答案的原始答案)没有满足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()函数替换为Shuffle函数,例如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衬里相同(当然,这是很长且很丑的线条,如果使用适当的随机播放功能,则不会成为1衬里。不推荐,但有时还是很有趣):

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永远不会出现在您生成的任何密码中。
瑞安·希灵顿

1
谢谢。我在OP问题中使用了字符集,但看起来有缺陷。现在更新。
mwag'4

您说“这比接受/投票最高的答案更安全”。您能详细说明原因吗?
本杰明·

Math.random()的使用也是可以预测的。因此,最好使用诸如window.crypto.getRandomValues之类的函数来生成密码。
本杰明·

2
它更安全的原因是,与使用toString(36)相比,它支持在输出中包含更多可能的字符。使用固定的输出长度(例如8个),如果您最多可以选择36个字符,那么排列的数量将比如果您有62个字符(如示例中)的数量少得多,或者甚至更好,整个95个可打印字符(ascii) )字符,或者如果使用unicode,则每个字节的可能性更高。
mwag '17

10

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

根据mwag的答案,但此方法使用crypto.getRandomValues的随机性要强于Math.random

Array(20)
  .fill('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~!@-#$')
  .map(x => x[Math.floor(crypto.getRandomValues(new Uint32Array(1))[0] / (0xffffffff + 1) * x.length)])
  .join('');

0xffffffff

选择1

var generatePassword = (
  length = 20,
  wishlist = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~!@-#$"
) => Array(length)
      .fill('')
      .map(() => wishlist[Math.floor(crypto.getRandomValues(new Uint32Array(1))[0] / (0xffffffff + 1) * wishlist.length)])
      .join('');

console.log(generatePassword());

选择2

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

console.log(generatePassword())

Node.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())

1
由于偏移量未定义,因此无法始终提供20个长度的密码。该+ 1零件不是必需的,可以删除。
bryc

好抓@bryc。更新。谢谢。
Ninh Pham

1
有用且简单的解决方案。希望在NodeJS中执行此操作的任何人都可以简单地crypto.getRandomValuescrypto.randomFillSync替换。
Rvy Pandey

添加了Node.js版本。谢谢@Rvy Pandey。
Ninh Pham

8

并没有完全优化,但是应该可以。

var chars = "ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
var string_length = 8;
var randomstring = '';
var charCount = 0;
var numCount = 0;

for (var i=0; i<string_length; i++) {
    // If random bit is 0, there are less than 3 digits already saved, and there are not already 5 characters saved, generate a numeric value. 
    if((Math.floor(Math.random() * 2) == 0) && numCount < 3 || charCount >= 5) {
        var rnum = Math.floor(Math.random() * 10);
        randomstring += rnum;
        numCount += 1;
    } else {
        // If any of the above criteria fail, go ahead and generate an alpha character from the chars string
        var rnum = Math.floor(Math.random() * chars.length);
        randomstring += chars.substring(rnum,rnum+1);
        charCount += 1;
    }
}

alert(randomstring);

​ ​ ​

这是一个供您测试的jsfiddle:http : //jsfiddle.net/sJGW4/3/


1
chars.substring(rnum, rnum+1)就像chars.charAt(rnum)
Mad Echet

7

如果您需要使用至少1个数字,1个大写字母和1个小写字母生成的密码:

function generatePassword(passwordLength) {
  var numberChars = "0123456789";
  var upperChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  var lowerChars = "abcdefghijklmnopqrstuvwxyz";
  var allChars = numberChars + upperChars + lowerChars;
  var randPasswordArray = Array(passwordLength);
  randPasswordArray[0] = numberChars;
  randPasswordArray[1] = upperChars;
  randPasswordArray[2] = lowerChars;
  randPasswordArray = randPasswordArray.fill(allChars, 3);
  return shuffleArray(randPasswordArray.map(function(x) { return x[Math.floor(Math.random() * x.length)] })).join('');
}

function shuffleArray(array) {
  for (var i = array.length - 1; i > 0; i--) {
    var j = Math.floor(Math.random() * (i + 1));
    var temp = array[i];
    array[i] = array[j];
    array[j] = temp;
  }
  return array;
}

alert(generatePassword(12));

如果您想玩/测试,这里是小提琴:http : //jsfiddle.net/sJGW4/155/

@mwag的道具,让我开始创建它。


1
您缺少小写字母j:P否则,这里的好东西。对其进行了一些修改以满足我的要求。
伊戈尔·亚维奇

7

如@RobW所述,按照OP方案中的建议将密码限制为固定数量的字符是一个坏主意。但是更糟糕的是,提出基于代码的答案是Math.random一个非常糟糕的主意

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

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

但是足够的坏。让我们提出一条前进的道路。我将使用JavaScript EntropyString库,该库“有效地从各种字符集中生成具有指定熵的加密强随机字符串”。我将使用32种字符集而不是OP 62字符集,以减少易混淆字符的使用或减少英语单词的形成。而不是5字母3的数字方案(熵太小),我将宣布密码将具有60位的熵(这是易用性与价值的平衡)。

import {Random, charSet32} from 'entropy-string'
const random = new Random(charSet32)
const string = random.string(60)

“ Q7LfR8Jn7RDp”

请注意,参数to random.string是所需的熵位,与更常见的随机字符串生成解决方案相反,该解决方案指定传递字符串长度(这既被误导,也通常未指定,但这是另一回事了)。


6

我写了一本小书,灵感来自您的答案:

(function(){g=function(){c='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';p='';for(i=0;i<8;i++){p+=c.charAt(Math.floor(Math.random()*62));}return p;};p=g();while(!/[A-Z]/.test(p)||!/[0-9]/.test(p)||!/[a-z]/.test(p)){p=g();}return p;})()

此函数返回密码,可以在书签中使用,例如:

javascript:alert(TheCodeOfTheFunction);

3

我不建议您使用强制密码,因为它会限制用户的安全性,但是无论如何,有几种方法可以使用它-

传统JavaScript方法-

Math.random().toString(36).slice(-8);

使用随机字符串

安装随机字符串:

npm install randomstring

在App.js中使用它-

var randStr = require('randomstring');

var yourString = randStr.generate(8);

密码的值保留在变量中yourString

不要使用强制密码!

强制密码可能会损害您的安全性,因为所有密码都使用相同的字符集,很容易被破坏!


3

好的,如果我能很好地理解您正在尝试获取一个随机字符串密码,该密码包含5个字母和3个随机放置的数字,因此长度为8个字符,并且您接受maj和min字母,则可以使用以下功能来实现:

function randPass(lettersLength,numbersLength) {
    var j, x, i;
    var result           = '';
    var letters       = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    var numbers       = '0123456789';
    for (i = 0; i < lettersLength; i++ ) {
        result += letters.charAt(Math.floor(Math.random() * letters.length));
    }
    for (i = 0; i < numbersLength; i++ ) {
        result += numbers.charAt(Math.floor(Math.random() * numbers.length));
    }
    result = result.split("");
    for (i = result.length - 1; i > 0; i--) {
        j = Math.floor(Math.random() * (i + 1));
        x = result[i];
        result[i] = result[j];
        result[j] = x;
    }
    result = result.join("");
    return result
}

function randPass(lettersLength,numbersLength) {
    var j, x, i;
    var result           = '';
    var letters       = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    var numbers       = '0123456789';
    for (i = 0; i < lettersLength; i++ ) {
        result += letters.charAt(Math.floor(Math.random() * letters.length));
    }
    for (i = 0; i < numbersLength; i++ ) {
        result += numbers.charAt(Math.floor(Math.random() * numbers.length));
    }
    result = result.split("");
    for (i = result.length - 1; i > 0; i--) {
        j = Math.floor(Math.random() * (i + 1));
        x = result[i];
        result[i] = result[j];
        result[j] = x;
    }
    result = result.join("");
    return result
}
console.log(randPass(5,3))


2
var letters = ['a','b','c','d','e','f','g','h','i','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'];
    var numbers = [0,1,2,3,4,5,6,7,8,9];
    var randomstring = '';

        for(var i=0;i<5;i++){
            var rlet = Math.floor(Math.random()*letters.length);
            randomstring += letters[rlet];
        }
        for(var i=0;i<3;i++){
            var rnum = Math.floor(Math.random()*numbers.length);
            randomstring += numbers[rnum];
        }
     alert(randomstring);

1

最后,无需使用浮点hack:

function genpasswd(n) {
    // 36 ** 11 > Number.MAX_SAFE_INTEGER
    if (n > 10)
        throw new Error('Too big n for this function');
    var x = "0000000000" + Math.floor(Number.MAX_SAFE_INTEGER * Math.random()).toString(36);
    return x.slice(-n);
}

1

带有一个upperCase字符的安全密码。

let once = false;

    let newPassword = Math.random().toString(36).substr(2, 8).split('').map((char) => {
                    if(!Number(char) && !once){
                        once = true;
                        return char.toUpperCase();
                    }
                    return char;
                }).join('');

    console.log(newPassword)

1

我的加密货币解决了这个问题。使用ES6并省略所有浏览器功能检查。对安全性或性能有何评论?

const generatePassword = (
  passwordLength = 12,
  passwordChars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
) =>
  [...window.crypto.getRandomValues(new Uint32Array(passwordLength))]
    .map(x => passwordChars[x % passwordChars.length])
    .join('');


1

创建一个名为PassswordGeneratorService的密码生成器服务

import { Injectable } from '@angular/core';

@Injectable()
export class PasswordGeneratorService {

  generatePassword(length:number,upper:boolean,numbers:boolean,symbols:boolean) {
    const passwordLength = length || 12;
    const addUpper =  upper;
    const addNumbers =  numbers;
    const addSymbols =  symbols;

    const lowerCharacters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
    const upperCharacters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
    const numbers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
    const symbols = ['!', '?', '@'];

    const getRandom = array => array[Math.floor(Math.random() * array.length)];

    let finalCharacters = '';

    if (addUpper) {
      finalCharacters = finalCharacters.concat(getRandom(upperCharacters));
    }

    if (addNumbers) {
      finalCharacters = finalCharacters.concat(getRandom(numbers));
    }

    if (addSymbols) {
      finalCharacters = finalCharacters.concat(getRandom(symbols));
    }

    for (let i = 1; i < passwordLength - 3; i++) {
      finalCharacters = finalCharacters.concat(getRandom(lowerCharacters));
    }

    return  finalCharacters.split('').sort(() => 0.5 - Math.random()).join('');
  }
}

不要忘记在您使用的模块上添加服务

@NgModule({
  imports: [
    CommonModule,
    SharedModule,
    CommonModule,
    RouterModule.forChild(routes),
    FormsModule,
    ReactiveFormsModule,
    FlexLayoutModule,
    TranslateModule,
    ExistingUserDialogModule,
    UserDocumentsUploadDialogModule
  ],
  declarations: [
    UserListComponent,
    EditUserDialogComponent,
    UserEditorComponent
  ],
  entryComponents: [
    EditUserDialogComponent
  ],
  providers: [
    AuthService,
    PasswordGeneratorService
  ]
})
export class UsersModule {
}

在您的控制器上,添加一个方法,该方法在服务内部调用generate password方法,并在password字段上设置结果

  constructor(
     private passwordGenerator: PasswordGeneratorService,
    )
  get newPassword() {
    return this.password.get('newPassword');
  }
  generatePassword() {
    this.newPassword.setValue(this.passwordGenerator.generatePassword(8,true,true,true));
  }

我只是剥离了函数generatePassword并使用了它,不需要整个类。thnx
Biskrem Muhammad

0

有一个具有选定长度的随机密码字符串生成器

let input = document.querySelector("textarea");
let button = document.querySelector("button");
let length = document.querySelector("input");

function generatePassword(n) 
{
	let pwd = "";

  while(!pwd || pwd.length < n)
  {
  	pwd += Math.random().toString(36).slice(-22);
  }
  
  return pwd.substring(0, n);
}

button.addEventListener("click", function()
{
	input.value = generatePassword(length.value);
});
<div>password:</div>
<div><textarea cols="70" rows="10"></textarea></div>
<div>length:</div>
<div><input type="number" value="200"></div>
<br>
<button>gen</button>


0

好吧,您始终可以使用最新版本浏览器中可用的window.crypto对象。

只需一行代码即可获得一个随机数:

let n = window.crypto.getRandomValues(new Uint32Array(1))[0];

它还有助于加密和解密数据。有关更多信息,请访问MDN Web docs-window.crypto

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.