Forcing a fixed number of characters is a bad idea. It doesn't improve the quality of the password. Worse, it reduces the number of possible passwords, so that hacking by bruteforcing becomes easier.
To generate a random word consisting of alphanumeric characters, use:
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"
Documentation for the Number.prototype.toString
and string.prototype.slice
methods.
A little more maintainable and secure approach.
An update to expand on what I meant and how it works.
Secure. MDN is pretty explicit about the use of Math.random
for anything related to security:
Math.random()
does not provide cryptographically secure random numbers. Do not use them for anything related to security. Use the Web Crypto API instead, and more precisely thewindow.crypto.getRandomValues()
method.
Looking at the can-i-use for getRandomValues
in 2020 you probably don't need the msCrypto
and Math.random
fallback any more, unless you care about ancient browsers.
Maintainable is mostly about the RegExp
_pattern
as an easy way to define what character classes you allow in the password. But also about the 3 things where each does its job: defines a pattern, gets a random byte as securely as possible, provides a public API to combine the two.
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)'>
Many answers (including the original of this one) don't address the letter- and number-count requirements of the OP. Below are two solutions: general (no min letters/numbers), and with rules.
I believe this is better general solution than the above, because:
Note that
Three-liner:
var pwdChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
var pwdLen = 10;
var randPassword = Array(pwdLen).fill(pwdChars).map(function(x) { return x[Math.floor(Math.random() * x.length)] }).join('');
Or, as one-liner:
var randPassword = Array(10).fill("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz").map(function(x) { return x[Math.floor(Math.random() * x.length)] }).join('');
Now, a variation on the above. This will generate three random strings from the given charsets (letter, number, either) and then scramble the result.
Please note the below uses sort() for illustrative purposes only. For production use, replace the below sort() function with a shuffle function such as Durstenfeld.
First, as a function:
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);
Same thing, as a 2-liner (admittedly, very long and ugly lines-- and won't be a 1-liner if you use a proper shuffle function. Not recommended but sometimes it's fun anyway) :
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('');
For someone who is looking for a simplest script. No while (true)
, no if/else
, no declaration.
Base on mwag's answer, but this one uses crypto.getRandomValues
, a stronger random than 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(""))())
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())
#!/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))
See: https://stackoverflow.com/a/67035900/1099314
As @RobW notes, restricting the password to a fixed number of characters as proposed in the OP scheme is a bad idea. But worse, answers that propose code based on Math.random
are, well, a really bad idea.
Let's start with the bad idea. The OP code is randomly selecting a string of 8 characters from a set of 62. Restricting the random string to 5 letters and 3 numbers means the resulting passwords will have, at best, 28.5 bits of entropy (as opposed to a potential of 47.6 bits if the distribution restriction of 5 letters and 3 numbers were removed). That's not very good. But in reality, the situation is even worse. The at best aspect of the code is destroyed by the use of Math.random
as the means of generating entropy for the passwords. Math.random
is a pseudo random number generator. Due to the deterministic nature of pseudo random number generators the entropy of the resulting passwords is really bad , rendering any such proposed solution a really bad idea. Assuming these passwords are being doled out to end users (o/w what's the point), an active adversary that receives such a password has very good chance of predicting future passwords doled out to other users, and that's probably not a good thing.
But back to the just bad idea. Assume a cryptographically strong pseudo random number generator is used instead of Math.random
. Why would you restrict the passwords to 28.5 bits? As noted, that's not very good. Presumably the 5 letters, 3 numbers scheme is to assist users in managing randomly doled out passwords. But let's face it, you have to balance ease of use against value of use, and 28.5 bits of entropy isn't much value in defense against an active adversary.
But enough of the bad. Let's propose a path forward. I'll use the JavaScript EntropyString library which "efficiently generates cryptographically strong random strings of specified entropy from various character sets". Rather than the OP 62 characters, I'll use a character set with 32 characters chosen to reduce the use of easily confused characters or the formation of English words. And rather than the 5 letter, 3 number scheme (which has too little entropy), I'll proclaim the password will have 60 bits of entropy (this is the balance of ease versus value).
import { Entropy, charSet32 } from 'entropy-string'
const random = new Entropy({ bits: 60, charset: charset32 })
const string = random.string()
"Q7LfR8Jn7RDp"
Note the arguments to Entropy
specify the desired bits of entropy as opposed to more commonly seen solutions to random string generation that specify passing in a string length (which is both misguided and typically underspecified, but that's another story).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With