Безопасный случайный токен в Node.js - PullRequest
232 голосов
/ 13 января 2012

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

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

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

Ответы [ 11 ]

316 голосов
/ 13 января 2012

Попробуйте crypto.randomBytes () :

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

Шестнадцатеричное кодирование работает в узле v0.6.x или новее.

200 голосов
/ 13 августа 2014

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

var token = crypto.randomBytes(64).toString('hex');
68 голосов
/ 05 сентября 2014

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

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

https://github.com/ai/nanoid

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


1. Кодировка Base 64 с URL и именем файла Безопасный алфавит

Страница 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.

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


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.
10 голосов
/ 09 мая 2017

Современный правильный способ сделать это асинхронно с использованием стандартов асинхронного и ожидающего ES 2016 (на Узле 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);
}

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

7 голосов
/ 15 марта 2016

Случайный URL и имя файла безопасны (1 строка)

Crypto.randomBytes(48).toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, '');
6 голосов
/ 31 июля 2017

С асинхронным ожиданием и обещанием .

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

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

5 голосов
/ 28 мая 2015

Посмотрите на 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'));
});
4 голосов
/ 21 января 2017

Выезд:

var crypto = require('crypto');
crypto.randomBytes(Math.ceil(length/2)).toString('hex').slice(0,length);
2 голосов
/ 05 августа 2016

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

Для генерации случайной строки в 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().

1 голос
/ 20 февраля 2016

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

var value = crypto.random(/* desired length */)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...