Proteger token aleatorio en Node.js

En esta pregunta, Erik necesita generar un token aleatorio seguro en Node.js. Existe el método crypto.randomBytes que genera un Buffer aleatorio. Sin embargo, la encoding base64 en el nodo no es segura para las url, incluye / y + lugar de - y _ . Por lo tanto, la forma más fácil de generar dicho token que he encontrado es

 require('crypto').randomBytes(48, function(ex, buf) { token = buf.toString('base64').replace(/\//g,'_').replace(/\+/g,'-'); }); 

¿Hay una manera más elegante?

Pruebe crypto.randomBytes () :

 require('crypto').randomBytes(48, function(err, buffer) { var token = buffer.toString('hex'); }); 

La encoding 'hexadecimal' funciona en el nodo v0.6.xo superior.

Opción sincrónica en caso de que no seas un experto en JS como yo. Tuve que pasar un time sobre cómo acceder a la variable de function en línea

 var token = crypto.randomBytes(64).toString('hex'); 

1. Base 64 de encoding con URL y nombre de file Safe Alphabet

La página 7 de RCF 4648 describe cómo codificar en la base 64 con security de URL. Puede usar una biblioteca existente como base64url para hacer el trabajo.

La function será:

 var crypto = require('crypto'); var base64url = require('base64url'); /** Sync */ function randomStringAsBase64Url(size) { return base64url(crypto.randomBytes(size)); } 

Ejemplo de uso:

 randomStringAsBase64Url(20); // Returns 'AXSGpLVjne_f7w5Xg-fWdoBwbfs' which is 27 characters length. 

Tenga en count que la longitud de la cadena devuelta no coincidirá con el argumento de tamaño (tamaño! = Longitud final).

2. Valores criptocharts aleatorios a partir de un set limitado de caracteres

Tenga en count que con esta solución, la cadena aleatoria generada no se distribuye uniformemente.

También puedes build una cadena aleatoria fuerte a partir de un set limitado de caracteres como ese:

 var crypto = require('crypto'); /** Sync */ function randomString(length, chars) { if (!chars) { throw new Error('Argument \'chars\' is undefined'); } var charsLength = chars.length; if (charsLength > 256) { throw new Error('Argument \'chars\' should not have more than 256 characters' + ', otherwise unpnetworkingictability will be broken'); } var randomBytes = crypto.randomBytes(length); var result = new Array(length); var cursor = 0; for (var i = 0; i < length; i++) { cursor += randomBytes[i]; result[i] = chars[cursor % charsLength]; } return result.join(''); } /** Sync */ function randomAsciiString(length) { return randomString(length, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'); } 

Ejemplo de uso:

 randomAsciiString(20); // Returns 'rmRptK5niTSey7NlDk5y' which is 20 characters length. randomString(20, 'ABCDEFG'); // Returns 'CCBAAGDGBBEGBDBECDCE' which is 20 characters length. 

La forma correcta y actualizada de hacer esto de forma asincrónica utilizando los estándares ES 2016 de async y await (a partir del Nodo 7) sería la siguiente:

 const crypto = require('crypto'); function generateToken({ stringBase = 'base64', byteLength = 48 } = {}) { return new Promise((resolve, reject) => { crypto.randomBytes(byteLength, (err, buffer) => { if (err) { reject(err); } else { resolve(buffer.toString(stringBase)); } }); }); } async function handler(req, res) { // default token length const newToken = await generateToken(); console.log('newToken', newToken); // pass in parameters - adjust byte length const shortToken = await generateToken({byteLength: 20}); console.log('newToken', shortToken); } 

Esto funciona fuera de la caja en el Nodo 7 sin ninguna transformación de Babel

Mira real_ates ES2016 manera, es más correcto.

Modo ECMAScript 2016 (ES7)

 import crypto from 'crypto'; function spawnTokenBuf() { return function(callback) { crypto.randomBytes(48, callback); }; } async function() { console.log((await spawnTokenBuf()).toString('base64')); }; 

Generator / Yield Way

 var crypto = require('crypto'); var co = require('co'); function spawnTokenBuf() { return function(callback) { crypto.randomBytes(48, callback); }; } co(function* () { console.log((yield spawnTokenBuf()).toString('base64')); }); 

Random URL y filename string safe (1 liner)

 Crypto.randomBytes(48).toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, ''); 

Revisa:

 var crypto = require('crypto'); crypto.randomBytes(Math.ceil(length/2)).toString('hex').slice(0,length); 

El module npm anyid proporciona una API flexible para generar varios types de ID / código de cadena.

Para generar cadena aleatoria en A-Za-z0-9 utilizando 48 bytes aleatorios:

 const id = anyid().encode('Aa0').bits(48 * 8).random().id(); // G4NtiI9OYbSgVl3EAkkoxHKyxBAWzcTI7aH13yIUNggIaNqPQoSS7SpcalIqX0qGZ 

Para generar una cadena de alfabeto de longitud fija llena de bytes aleatorios:

 const id = anyid().encode('Aa').length(20).random().id(); // qgQBBtDwGMuFHXeoVLpt 

Internamente usa crypto.randomBytes() para generar random.

Con async / await y promisification .

 const crypto = require('crypto') const randomBytes = Util.promisify(crypto.randomBytes) const plain = (await randomBytes(24)).toString('base64').replace(/\W/g, '') 

Genera algo similar a VjocVHdFiz5vGHnlnwqJKN0NdeHcz8eM

Aquí hay una versión asincrónica tomada literalmente de la respuesta anterior de @Yves M.

 var crypto = require('crypto'); function createCryptoString(length, chars) { // returns a promise which renders a crypto string if (!chars) { // provide default dictionary of chars if not supplied chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; } return new Promise(function(resolve, reject) { var charsLength = chars.length; if (charsLength > 256) { reject('parm chars length greater than 256 characters' + ' masks desinetworking key unpnetworkingictability'); } var randomBytes = crypto.randomBytes(length); var result = new Array(length); var cursor = 0; for (var i = 0; i < length; i++) { cursor += randomBytes[i]; result[i] = chars[cursor % charsLength]; } resolve(result.join('')); }); } // --- now generate crypto string async using promise --- / var wantStringThisLength = 64; // will generate 64 chars of crypto secure string createCryptoString(wantStringThisLength) .then(function(newCryptoString) { console.log(newCryptoString); // answer here }).catch(function(err) { console.error(err); }); 

https://www.npmjs.com/package/crypto-extra tiene un método para eso 🙂

 var value = crypto.random(/* desinetworking length */)