Node.js'de rasgele jeton alın


273

Gelen bu soruya Erik Node.js. güvenli bir rasgele kodu oluşturması gerekiyor crypto.randomBytesRastgele bir Tampon üreten yöntem var. Ancak, düğümdeki base64 kodlaması url için güvenli değildir, /ve +yerine -ve içerir _. Bu nedenle, bulduğum böyle bir jetonu oluşturmanın en kolay yolu

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

Daha zarif bir yol var mı?


Kodun geri kalanı nedir?
Lion789

3
Daha fazla bir şey gerekmiyor. Hangi dinlenmeyi görmek istersiniz?
Hubert OG

Boşver, işe aldım, onu nasıl attığından emin değildim, ama konsepti daha iyi anladım
Lion789

1
Utanmaz kendinden fiş, yine başka bir npm paketi oluşturdum: tokgen . İzin verilen karakterleri, normal ifadelerde karakter sınıflarına benzer bir aralık sözdizimi kullanarak belirleyebilirsiniz ( 'a-zA-Z0-9_-').
Max Truxa

1
Bu, belirli bir dize uzunluğu isteyen herkes için uygun olabilir. 3 / 4'ler taban dönüşümünü işlemek içindir. / *, base64 kodlu bir uzunluk dizesi döndürür * / function randomString (length) {return crypto.randomBytes (uzunluk * 3/4) .toString ('base64'); } Bu karakter sınırlamalarına sahip veritabanları için iyi çalışır.
TheUnknownGeek

Yanıtlar:


353

Crypto.randomBytes () yöntemini deneyin :

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

'Hex' kodlaması v0.6.x veya daha yeni düğümlerde çalışır.


3
Daha iyi görünüyor, teşekkürler! Yine de bir 'base64-url' kodlaması iyi olurdu.
Hubert OG

2
Bahşiş için teşekkürler, ancak OP zaten zaten standart RFC 3548 bölüm 4 "Base 64 URL ve Dosya Adı Güvenli Alfabesi ile Kodlama" istediğini düşünüyorum. IMO, karakterleri değiştirmek "yeterince zarif".
natevw

8
Yukarıdakileri bash bir astar olarak arıyorsanız, şunları yapabilirsiniznode -e "require('crypto').randomBytes(48, function(ex, buf) { console.log(buf.toString('hex')) });"
Dmitry Minkovsky

24
Ve her zaman buf.toString('base64')Base64 kodlu bir numara almak için yapabilirsiniz .
Dmitry Minkovsky

1
Bkz bu answser için aşağıdaki tabanı 64 kodlayan URL ve dosya adı Güvenli Alfabesi ile
Yves M.

232

Benim gibi bir JS uzmanı değilseniz, eşzamanlı seçenek. Satır içi işlev değişkenine erişim için biraz zaman harcamak zorunda kaldım

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

7
Ayrıca her şeyin iç içe geçmesini istemiyorsanız. Teşekkürler!
Michael Ozeryansky

2
Bu kesinlikle işe yarar olsa da, çoğu durumda async seçeneğinin cevabında gösterilmesini isteyeceğinizi unutmayın.
Triforcey

1
const generateToken = (): Promise<string> => new Promise(resolve => randomBytes(48, (err, buffer) => resolve(buffer.toString('hex'))));
yantrab

1
@Triforcey neden async seçeneğini neden istediğinizi açıklayabilir misiniz?
thomas

2
@ thomas Rastgele verilerin donanıma bağlı olarak hesaplanması biraz zaman alabilir. Bazı durumlarda, bilgisayar rasgele veriler tükenirse, yerine bir şey döndürür. Bununla birlikte, diğer durumlarda bilgisayar rastgele verilerin geri dönüşünü geciktirir (bu aslında istediğiniz şeydir) ve yavaş bir çağrı ile sonuçlanır.
Triforcey

80

0. Nanoid üçüncü taraf kütüphanesini kullanma [YENİ!]

JavaScript için küçük, güvenli, URL dostu, benzersiz bir dize kimliği oluşturucu

https://github.com/ai/nanoid

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


1. Base 64 URL ve Dosya Adı Güvenli Alfabesi ile Kodlama

Sayfa 7 / RCF 4648 , 64 numaralı URL'de URL güvenliği ile nasıl kodlanacağını açıklar. İşi yapmak için base64url gibi mevcut bir kütüphaneyi kullanabilirsiniz .

Fonksiyon şöyle olacaktır:

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

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

Kullanım örneği:

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

Döndürülen dize uzunluğunun boyut bağımsız değişkeniyle eşleşmeyeceğini unutmayın (boyut! = Son uzunluk).


2. Sınırlı karakter kümesinden rasgele değerleri şifreleme

Bu çözümle üretilen rastgele dizenin eşit olarak dağıtılmadığına dikkat edin.

Ayrıca, bunun gibi sınırlı bir karakter kümesinden güçlü bir rastgele dize oluşturabilirsiniz:

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

Kullanım örneği:

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

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

2
@Lexynux Solution 1 (Temel 64 URL ve Dosya Adı Güvenli Alfabesi ile Kodlama) çünkü güvenlik açısından en güçlü çözümdür. Bu çözüm sadece anahtarı kodlar ve anahtar üretim sürecine müdahale etmez.
Yves

Desteğin için teşekkürler. Toplulukla paylaşmak için çalışan bir örneğiniz var mı? Memnuniyetle olacak?
alexventuraio

6
Oluşturulan rastgele dizenin eşit dağılmadığına dikkat edin. Bunu göstermek için kolay bir örnek, 255 uzunluklu bir karakter kümesi ve 1 dize uzunluğu için, ilk karakterin ortaya çıkma şansının iki kat daha yüksek olmasıdır.
Florian Wendelborn

@Dodekeract Evet, çözüm 2 hakkında konuşuyorsunuz .. Bu yüzden çözüm 1 çok daha güçlü
Yves M.

Yanıtımda nanoid üçüncü taraf kütüphanesi ekledim github.com/ai/nanoid
Yves M.

13

ES 2016 zaman uyumsuz ve beklemedeki (Düğüm 7'den itibaren) standartlarını kullanarak bunu zaman uyumsuz olarak yapmanın güncel doğru yolu aşağıdaki gibi olacaktır:

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

Bu, Babil dönüşümü olmadan Düğüm 7'deki kutudan çıkar


Bu örneği, burada açıklandığı gibi adlandırılmış parametreleri geçirmenin
real_ate

7

Rastgele URL ve dosya adı dizesi güvenli (1 astar)

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

Sadeliğinde harika bir cevap! Olay döngüsünü belirsiz bir şekilde durdurabileceğini unutmayın (yalnızca sık sık, biraz yüklü, zamana duyarlı bir sistemde kullanılırsa). Aksi takdirde, aynı şeyi yapın, ancak randomBytes'in zaman uyumsuz sürümünü kullanarak. Bkz. Nodejs.org/api/…
Alec Thilenius

6

Çıkış yapmak:

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

Güzel! Kesinlikle çok az çözüm. "Length" değerini "desiredLength" olarak değiştirir ve kullanmadan önce bir değerle başlatırsanız harika olur :)
Florian Blum

Merak eden herkes için, ceilve sliceçağrıları garip olan istenen uzunluklar için gereklidir. Eşit uzunluklar için hiçbir şey değiştirmezler.
Seth

6

Zaman uyumsuz / beklenti ve vaat ile .

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

Şuna benzer bir şey üretir VjocVHdFiz5vGHnlnwqJKN0NdeHcz8eM


4

real_atesES2016'ya bakın, daha doğru.

ECMAScript 2016 (ES7) yolu

import crypto from 'crypto';

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

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

Jeneratör / Verim Yolu

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

@Jeffpowrs Gerçekten, Javascript yükseltiyor :) Arama Sözleri ve Jeneratörler!
K - SO'da toksisite artıyor.

başka bir ECMA7 söz işleyicisi bekliyor
Jain

Çoğu durumda "bunu yapmanın doğru yolu" na doğru ilerlerken ES 2016'yı bu konuda ilk örnek yapmalısınız
real_ate

Düğüm için özel olan kendi yanıtımı ekledim (içe aktarma yerine istem kullanarak). İçe aktarmayı kullanmanızın belirli bir nedeni var mıydı? Babil kaçıyor mu?
real_ate

@real_ate Gerçekten de, içe aktarma resmi olarak desteklenene kadar CommonJS kullanmaya geri döndüm.
K - SO'da toksisite artıyor.


2

Npm modülü anyid çeşitli dize kimliği / kodu üretmek için esnek API sağlar.

48 rastgele bayt kullanarak A-Za-z0-9'da rastgele dize oluşturmak için:

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

Sabit uzunluklu alfabe oluşturmak için yalnızca rastgele baytlarla doldurulmuş bir dize oluşturun:

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

Dahili crypto.randomBytes()olarak rastgele üretmek için kullanır .


1

İşte @Yves M.'nin cevabından kelimesi kelimesine alınmış bir zaman uyumsuz sürü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

URL güvenli ve base64 kodlaması olan bir jeton alır basit bir işlev! Yukarıdan 2 cevaptan oluşan bir kombinasyon.

const randomToken = () => {
    crypto.randomBytes(64).toString('base64').replace(/\//g,'_').replace(/\+/g,'-');
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.