web-dev-qa-db-ja.com

Node.js内の安全なランダムトークン

In この質問 ErikはNode.jsに安全なランダムトークンを生成する必要があります。ランダムなBufferを生成するメソッドcrypto.randomBytesがあります。ただし、nodeのbase64エンコーディングはURLセーフではなく、/および+の代わりに-および_が含まれています。したがって、私が見つけたそのようなトークンを生成する最も簡単な方法は

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

もっとエレガントな方法はありますか?

230
Hubert OG

試してください crypto.randomBytes()

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

'hex'エンコーディングはノードv0.6.x以降で動作します。

313
thejh

あなたが私のようなJSの専門家でないならば、同期オプション。インライン関数変数にアクセスする方法に時間をかけなければなりませんでした

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

0. nanoidサードパーティライブラリを使用する[NEW!]

JavaScript用の小さく安全でURLにやさしいユニークな文字列IDジェネレータ

https://github.com/ai/nanoid

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


1. URLとファイル名に安全なアルファベットを使用したBase 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));
}

使用例

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

返される文字列の長さは、サイズの引数と一致しません(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.
66
Yves M.

ES 2016のasyncとawait(Node 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);
}

これは、Babel変換を一切行わずに、ノード7の箱から出して動作します。

10
real_ate

ランダムなURLとファイル名の文字列を安全に(1行)

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

Async/awaitと promisification を使って。

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

VjocVHdFiz5vGHnlnwqJKN0NdeHcz8eMのようなものを生成します

6
Znarkus

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

チェックアウト:

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

Npmモジュール anyid は、さまざまな種類の文字列ID /コードを生成するための柔軟なAPIを提供します。

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()を使って乱数を生成します。

2
aleung

https://www.npmjs.com/package/crypto-extra そのための方法があります:)

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

これは上記の@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 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);
});
1
Scott Stensland