Try crypto.randomBytes():
require('crypto').randomBytes(48, function(err, buffer) {
var token = buffer.toString('hex');
});
The 'hex' encoding works in node v0.6.x or newer.
Updates for ES2021+ using Buffer
import {randomBytes} from "node:crypto";
function tokenGenerate(length=56) {
return Buffer.from(randomBytes(length)).toString('hex');
}
Answer from thejh on Stack Overflow
» npm install crypto-random-string
Try crypto.randomBytes():
require('crypto').randomBytes(48, function(err, buffer) {
var token = buffer.toString('hex');
});
The 'hex' encoding works in node v0.6.x or newer.
Updates for ES2021+ using Buffer
import {randomBytes} from "node:crypto";
function tokenGenerate(length=56) {
return Buffer.from(randomBytes(length)).toString('hex');
}
Synchronous option in-case if you are not a JS expert like me. Had to spend some time on how to access the inline function variable
var token = crypto.randomBytes(64).toString('hex');
Is this safe enough or am I making a horrible mistake?
Safe enough. Overkill, honestly. The most notable improvement I'd recommend here in particular is hashing the session token before storing it in the DB (or checking it against the DB-stored list of sessions). That way, even if an attacker gets a look at the DB, they couldn't steal somebody else's session. You should also enforce a server-side timeout for sessions, if you're going to have them time out at all.
Of course, there's a ton of other considerations that go into an authentication system (much less authorization). What credentials to use and how to verify them, how to handle loss of credentials (e.g. forgotten password), multi-factor auth, and so much more.
Also, specifically with cookies, you need to make sure your service is secure against CSRF (Cross-Site Request Forgery) attacks. There's a bunch of ways to do that but you do need to do at least one of them.
seems bad to me that it only uses 0-9 characters, it'd probably be much more secure if I used ASCII letters as well
Nope, that's actually pretty irrelevant. 16x UInt32 is 512 bits (64 bytes), which is excessively high entropy for a session token (most are in the 128-256 bits range, and every extra bit doubles the difficulty to brute-force the token). Representing it as decimal digits [0-9] isn't any less secure than representing it as hex [0-9A-F] or base64 [0-9A-Za-z./], and also isn't any more secure than representing it as octal [0-7] or even binary [0-1]. 64 bytes can be 512 binary digits, or 171 octal digits (including two bits of padding), or 155 decimal digits (again including some padding), or 128 hex digits, or 86 base64 digits (including some bits of padding, plus usually it would be further padded with two = for a total length of 88).
You see how the string gets shorter the wider the character set used? Yet they all have the exact same amount of unguessability (entropy).
Now, string concatenation of decimal values (without delimiters or padding) in particular is a bad way to handle this, because it does introduce ambiguities (simple example: the string "101234" could be formed by the numbers "101","234", or "10","1234", or "10","12","34", or... you get the idea), but it still doesn't matter. Even if we assume that the string randomly ended up only 100 digits long - less likely than correctly picking a randomly selected atom of the planet Earth - it would still ludicrously unguessable (279-332 bits of entropy, far stronger than the encryption keys used for financial communications).
Here is a simple html web page that uses the javascript Crypto.getRandomValues() function to create a random 32-byte hexadecimal string:
<html lang="en">
<head>
<meta charset="utf-8">
<title>Random String Generator</title>
</head>
<body>
<h3>Random String Generator</h3>
<script>
document.write(bytestohex(window.crypto.getRandomValues(new Uint8Array(32))));
function bytestohex(bytes) {
var hexstring='', h;
for(var i=0; i<bytes.length; i++) {
h=bytes[i].toString(16);
if(h.length==1) { h='0'+h; }
hexstring+=h;
}
return hexstring;
}
</script>
</body>
</html>
I think this will work for you:
function makeid(length) {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for ( var i = 0; i < length; i++ ) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
console.log(makeid(5));
//Can change 7 to 2 for longer results.
let r = (Math.random() + 1).toString(36).substring(7);
console.log("random", r);
Note: The above algorithm has the following weaknesses:
- It will generate anywhere between 0 and 6 characters due to the fact that trailing zeros get removed when stringifying floating points.
- It depends deeply on the algorithm used to stringify floating point numbers, which is horrifically complex. (See the paper "How to Print Floating-Point Numbers Accurately".)
Math.random()may produce predictable ("random-looking" but not really random) output depending on the implementation. The resulting string is not suitable when you need to guarantee uniqueness or unpredictability.- Even if it produced 6 uniformly random, unpredictable characters, you can expect to see a duplicate after generating only about 50,000 strings, due to the birthday paradox. (sqrt(36^6) = 46656)