在节点.js中保护随机令牌

Secure random token in Node.js

本文关键字:随机 令牌 保护 节点 js      更新时间:2023-09-26

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

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

还有比这更优雅的方式吗?

试试 crypto.randomBytes((:

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

"十六进制"编码适用于节点 v0.6.x 或更高版本。

如果您不是像我这样的 JS 专家,则为同步选项。不得不花一些时间在如何访问内联函数变量上

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

1. 使用纳米第三方库 [新!

<小时 />

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

https://github.com/ai/nanoid

import { nanoid } from "nanoid";
const id = nanoid(48);

2. 使用 URL 和文件名安全字母进行 Base 64 编码

<小时 />

RCF 4648 的第 7 页介绍了如何使用 URL 安全在 base 64 中进行编码。

Node.js>=v14.18.0 原生支持此功能:

const crypto = require("crypto");
/** Sync */
function randomStringAsBase64Url(size) {
  return crypto.randomBytes(size).toString("base64url");
}

使用示例:

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

请注意,返回的字符串长度将与 size 参数不匹配(size != 最终长度(。

如果您使用的是 Node.js

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

3. 来自有限字符集的加密随机值

<小时 />

请注意,使用此解决方案,生成的随机字符串不是均匀分布的。

您还可以从一组有限的字符中构建一个强大的随机字符串,如下所示:

const crypto = require("crypto");
/** Sync */
function randomString(length, chars) {
  if (!chars) {
    throw new Error("Argument 'chars' is undefined");
  }
  const charsLength = chars.length;
  if (charsLength > 256) {
    throw new Error("Argument 'chars' should not have more than 256 characters"
      + ", otherwise unpredictability will be broken");
  }
  const randomBytes = crypto.randomBytes(length);
  let result = new Array(length);
  let cursor = 0;
  for (let 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 异步和等待标准(从节点 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 中开箱即用,无需任何 Babel 转换

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

const token = crypto.randomBytes(48).toString('base64url');

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

const randomBytesAsync = util.promisify(crypto.randomBytes);
const token = (await randomBytesAsync(48)).toString('base64url');

随机 URL 和文件名字符串安全(1 行(

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

with async/await and promisization。

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

生成类似于VjocVHdFiz5vGHnlnwqJKN0NdeHcz8eM的内容

退房:

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

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'

如果您想获得promisecryptoRandomString.async(options)添加.async

看看real_ates ES2016的方式,它更正确。

ECMAScript 2016 (ES7( 方式

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

终端中只需写

node -e "console.log(crypto.randomBytes(48).toString('hex'))"

或者在代码中使用:

const randomToken = () => {
   crypto.randomBytes(48).toString('hex');
}

https://www.npmjs.com/package/crypto-extra 有一个方法:)

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

npm 模块 anyid 提供了灵活的 API 来生成各种字符串 ID/代码。

要使用 48 个随机字节在 A-Za-z0-9 中生成随机字符串:

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

要生成由随机字节填充的固定长度的仅字母字符串:

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

在内部,它使用crypto.randomBytes()来生成随机。

简单的函数,为您提供URL安全且具有base64编码的令牌!这是上面 2 个答案的组合。

const randomToken = () => {
    crypto.randomBytes(64).toString('base64').replace(/'//g,'_').replace(/'+/g,'-');
}

0 无依赖的解决方案...适用于浏览器,deno和nodejs(使用新的全球网络加密(

const random = size => btoa(
  String.fromCharCode(
    ...crypto.getRandomValues(
      new Uint8Array(size)
    )
  )
).replaceAll('+', 'x').replaceAll('/', 'I').slice(0, size)
for (let i = 5; i--;) console.log(random(16))

所有 doe 我只会使用一个 uint8array ''w 预定义的长度,并在我需要 uniq 时调用crypto.getRandomValues(如果有必要,可以切片(,并且从不处理字符串或 base64,base64 只是不必要的开销。(为快速分配大量缓冲区可能代价高昂(

const buf256 = new Uint8Array(256)
const random = crypto.getRandomValues.bind(crypto, buf256)
for (let i = 5; i--;) random()//.slice()

您可以使用random-token。 它非常易于使用。 :)

var randomToken = require('random-token').create('abcdefghijklmnopqrstuvwxzyABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789');
var token = randomToken(16);

而且您也不能使用不同的盐

var randomToken = require('random-token');
var token = randomToken(16); // output -> d8d4kd29c40f021 ```