Безопасный случайный токен в узле.js



на этот вопрос Эрик должен создать безопасный случайный маркер в узле.js. Вот это метод crypto.randomBytes это создает случайный буфер. Однако кодировка base64 в узле не является безопасной для url, она включает / и + вместо - и _. Поэтому самый простой способ создать такой токен, который я нашел, - это



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


есть ли более элегантный способ?

845   11  

11 ответов:

попробовать крипто.randomBytes ():

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

кодировка ' hex ' работает в узле v0.6.X или новее.

синхронный вариант в случае, если вы не являетесь экспертом JS, как я. Пришлось потратить некоторое время на то, как получить доступ к встроенной переменной функции

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

0. Использование nanoid сторонней библиотеки [NEW!]

крошечный, безопасный, удобный для URL, уникальный генератор идентификаторов строк для JavaScript

https://github.com/ai/nanoid

const nanoid = require("nanoid");
const id = nanoid(48);


1. Кодировка Base 64 с URL и именем файла Safe Alphabet

Страница 7 из RCF 4648 описывает, как кодировать в базе 64 с безопасностью URL. Вы можете использовать существующую библиотеку, как base64url чтобы сделать работу.

функции:

var crypto = require('crypto');
var base64url = require('base64url');

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

пример использования:

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

обратите внимание, что возвращенная длина строки не будет совпадать с аргументом size (size != конечная длина).


2. Крипто случайные значения из ограниченного набора символов

помните, что при таком решении генерируемая случайная строка распределяется неравномерно.

вы также можно построить сильную случайную строку из ограниченного набора символов, например:

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 unpredictability 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');
}

пример использования:

randomAsciiString(20);
// Returns 'rmRptK5niTSey7NlDk5y' which is 20 characters length.

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

вверх-к-дата правильно чтобы сделать это асинхронно, используя стандарты ES 2016 async и await (начиная с узла 7) , будет следующим:

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);
}

это работает из коробки в узле 7 без каких-либо преобразований Бабеля

случайный URL и строка имени файла safe (1 liner)

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

посмотреть real_ates ES2016 путь, это более правильно.

ECMAScript 2016 (ES7) way

import crypto from 'crypto';

function spawnTokenBuf() {
    return function(callback) {
        crypto.randomBytes(48, callback);
    };
}

async function() {
    console.log((await spawnTokenBuf()).toString('base64'));
};

Генератор / Выход Путь

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

проверить:

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

С async/await и promisification.

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

создает что-то похожее на VjocVHdFiz5vGHnlnwqJKN0NdeHcz8eM

вот асинхронная версия, взятая дословно сверху @Yves M.'s answer

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 desired key unpredictability');
        }

        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);
});

модуль npm anyid обеспечивает гибкий API для генерации различных видов строки ID / кода.

для генерации случайной строки В A-Za-z0-9 с использованием 48 случайных байтов:

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

для генерации алфавита фиксированной длины только строка, заполненная случайными байтами:

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

внутренне он использует crypto.randomBytes() для генерации случайных.

https://www.npmjs.com/package/crypto-extra имеет метод для этого :)

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

Comments

    Ничего не найдено.