在Node.js中保护随机令牌

Hub*_* OG 248 javascript base64 securestring node.js

这个问题中, Erik需要在Node.js中生成一个安全的随机令牌.有crypto.randomBytes生成随机缓冲区的方法.但是,节点中的base64编码不是url-safe,它包含/+不是-_.因此,生成此类令牌的最简单方法是我发现的

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

有更优雅的方式吗?

the*_*ejh 334

尝试crypto.randomBytes():

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

'hex'编码在节点v0.6.x或更新版本中有效.

  • 你可以随时使用`buf.toString('base64')`来获得Base64编码的数字. (22认同)
  • 如果你正在寻找上面的bash one-liner,你可以做`node -e"require('crypto').randomBytes(48,function(ex,buf){console.log(buf.toString(' hex'))});"` (8认同)
  • 那似乎更好,谢谢!但是,'base64-url'编码会很好. (3认同)
  • Dmitry 出色的单行代码的稍微紧凑的版本:`node -p "require('crypto').randomBytes(48).toString('hex');"`(如果需要,将 `base64` 替换为 `hex`) (3认同)
  • 感谢您的提示,但我认为OP只是想要已经标准的RFC 3548第4节"Base 64 Encoding with URL and Filename Safe Alphabet".IMO,取代人物是"足够优雅". (2认同)
  • @MuhammadUmer,假设您仍在使用本示例中生成的所有 48 个字节,则十六进制字符串将比 Base64 字符串长,但具有相同的随机性 (2认同)

pho*_*010 215

如果您不是像我这样的JS专家,请同步选项.不得不花一些时间来访问内联函数变量

var token = crypto.randomBytes(64).toString('hex');
Run Code Online (Sandbox Code Playgroud)

  • 如果您不希望嵌套所有内容.谢谢! (5认同)
  • 虽然这绝对有效,但请注意,在大多数情况下,您需要在 jh 的答案中演示 async 选项。 (5认同)
  • `const generateToken = (): Promise<string> => new Promise(resolve => randomBytes(48, (err, buffer) => resolve(buffer.toString('hex'))));` (2认同)
  • @Triforcey你能解释一下为什么你通常需要异步选项吗? (2认同)
  • @thomas 随机数据可能需要一段时间才能计算,具体取决于硬件。在某些情况下,如果计算机用完随机数据,它只会在其位置返回一些内容。然而,在其他情况下,计算机可能会延迟随机数据的返回(这实际上是您想要的),从而导致调用缓慢。 (2认同)

Yve*_* M. 73

0.使用nanoid第三方库[新!]

一个小巧,安全,URL友好,唯一的JavaScript字符串ID生成器

https://github.com/ai/nanoid

const nanoid = require("nanoid");
const id = nanoid(48);
Run Code Online (Sandbox Code Playgroud)


1.使用URL和文件名安全字母表进行基本64编码

RCF 4648的第7页描述了如何使用URL安全性在base 64中进行编码.您可以使用像base64url这样的现有库来完成这项工作.

该功能将是:

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

/** Sync */
function randomStringAsBase64Url(size) {
  return base64url(crypto.randomBytes(size));
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

randomStringAsBase64Url(20);
// Returns 'AXSGpLVjne_f7w5Xg-fWdoBwbfs' which is 27 characters length.
Run Code Online (Sandbox Code Playgroud)

请注意,返回的字符串长度与size参数(size!= final 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');
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

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

randomString(20, 'ABCDEFG');
// Returns 'CCBAAGDGBBEGBDBECDCE' which is 20 characters length.
Run Code Online (Sandbox Code Playgroud)

  • 请注意,生成的随机字符串不是均匀分布的.显示这一点的一个简单示例是,对于长度为255且字符串长度为1的字符集,第一个字符出现的几率是两倍. (6认同)
  • @Lexynux **解决方案1 ​​*(带有URL和文件名安全字母的Base 64编码),因为它是安全性最强的解决方案。该解决方案仅对密钥进行编码,并且不会干扰密钥生产过程。 (2认同)
  • @AlexeySh。有点难以记住,因为那是近十年前的事了。我认为这是关于仅使用 mod/divisionrest 来散列您从随机性中获得的字符的危险。例如,如果您滚动一个随机字节 (0-255),然后仅提供 255 个可能的字符,则随机 0 = 随机 255 = 第一个可能的字符,因此它不统一 (2认同)

Ink*_*ing 22

从 Node.js 14.18 和 15.7 开始,内置了url 安全的 base64 编码支持:

const token = crypto.randomBytes(48).toString('base64url');
Run Code Online (Sandbox Code Playgroud)

如果您想使用异步版本(因为该函数可能必须等待熵),可以承诺它可以更好地与现代模式保持一致:

const randomBytesAsync = util.promisify(crypto.randomBytes);

const token = (await randomBytesAsync(48)).toString('base64url');
Run Code Online (Sandbox Code Playgroud)


rea*_*ate 11

使用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);
}
Run Code Online (Sandbox Code Playgroud)

这在Node 7中开箱即用,没有任何Babel转换


Has*_*alp 8

crypto-random-string是一个很好的模块。

const cryptoRandomString = require('crypto-random-string');
 
cryptoRandomString({length: 10});                          // => '2cf05d94db'
cryptoRandomString({length: 10, type: 'base64'});          // => 'YMiMbaQl6I'
cryptoRandomString({length: 10, type: 'url-safe'});        // => 'YN-tqc8pOw'
cryptoRandomString({length: 10, type: 'numeric'});         // => '8314659141'
cryptoRandomString({length: 6, type: 'distinguishable'});  // => 'CDEHKM'
cryptoRandomString({length: 10, type: 'ascii-printable'}); // => '`#Rt8$IK>B'
cryptoRandomString({length: 10, type: 'alphanumeric'});    // => 'DMuKL8YtE7'
cryptoRandomString({length: 10, characters: 'abc'});       // => 'abaaccabac'
Run Code Online (Sandbox Code Playgroud)

cryptoRandomString.async(options).async如果您想获得一个,请添加promise.


小智 7

随机URL和文件名字符串安全(1个班轮)

Crypto.randomBytes(48).toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, '');
Run Code Online (Sandbox Code Playgroud)


Zna*_*kus 6

随着异步/等待和承诺

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

产生类似于 VjocVHdFiz5vGHnlnwqJKN0NdeHcz8eM


小智 5

查看:

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


Kve*_*lav 5

在你的终端中只需写

node -e "console.log(crypto.randomBytes(48).toString('hex'))"
Run Code Online (Sandbox Code Playgroud)

或者在您的代码中使用:

const randomToken = () => {
   crypto.randomBytes(48).toString('hex');
}
Run Code Online (Sandbox Code Playgroud)