Node.js में यादृच्छिक टोकन सुरक्षित करें


273

में इस सवाल का एरिक Node.js. में एक सुरक्षित यादृच्छिक टोकन जेनरेट करने की जरूरत है वहाँ एक विधि है crypto.randomBytesकि एक यादृच्छिक बफर उत्पन्न करता है। हालाँकि, नोड में बेस 64 एन्कोडिंग url- सुरक्षित नहीं है, इसमें शामिल है /और +इसके बजाय -और _। इसलिए, मैंने पाया है कि इस तरह के टोकन उत्पन्न करने का सबसे आसान तरीका है

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

वहाँ एक और अधिक सुंदर तरीका है?


बाकी कोड क्या है?
लायन 789

3
ज्यादा जरूरत नहीं है। आप क्या आराम देखना चाहेंगे?
ह्यूबर्ट OG

कोई बात नहीं, मुझे यह काम करने के लिए मिला, आप इसे कैसे
फेंकते हैं

1
बेशर्म स्व-प्लग, मैंने अभी तक एक और एनपीएम पैकेज बनाया: टोकेगन । आप नियमित अभिव्यक्तियों ( 'a-zA-Z0-9_-') में वर्ण वर्गों के समान सीमा सिंटैक्स का उपयोग करके अनुमत वर्ण निर्दिष्ट कर सकते हैं ।
मैक्स Truxa

1
यह किसी के लिए सुविधाजनक हो सकता है जो एक विशिष्ट स्ट्रिंग लंबाई पसंद करेगा। आधार रूपांतरण को संभालने के लिए 3 / 4th है। / * एक base64 लंबाई का एन्कोडेड स्ट्रिंग देता है * / function randomString (लंबाई) {वापसी crypto.randomBytes (लंबाई * 3/4) .toString ('base64'); } उन डेटाबेस के लिए उन चरित्र सीमाओं के साथ अच्छा काम करता है।
TheUnognGeek

जवाबों:


353

Crypto.randomBytes का प्रयास करें () :

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

'हेक्स' एन्कोडिंग नोड v0.6.x या नए में काम करता है।


3
यह बेहतर लगता है, धन्यवाद! एक 'base64-url' एन्कोडिंग हालांकि अच्छा होगा।
ह्यूबर्ट ओजी

2
टिप के लिए धन्यवाद, लेकिन मुझे लगता है कि ओपी बस पहले से ही मानक RFC 3548 खंड 4 "URL और फ़ाइल नाम सुरक्षित वर्णमाला के साथ बेस 64 एनकोडिंग" चाहता था। IMO, वर्णों की जगह "सुरुचिपूर्ण पर्याप्त" है।
natevw

8
यदि आप बैश वन-लाइनर के रूप में ऊपर की तलाश कर रहे हैं, तो आप कर सकते हैंnode -e "require('crypto').randomBytes(48, function(ex, buf) { console.log(buf.toString('hex')) });"
दिमित्री मिंकोवस्की

24
और आप हमेशा buf.toString('base64')बेस 64-एनकोडेड नंबर प्राप्त कर सकते हैं ।
दिमित्री मिन्कोवस्की

1
URL और फ़ाइल नाम सुरक्षित वर्णमाला के साथ बेस 64 एन्कोडिंग के लिए नीचे इस उत्तरदाता को देखें
Yves M.

232

यदि आप मेरी तरह जेएस विशेषज्ञ नहीं हैं तो समकालिक विकल्प के मामले में। इनलाइन फ़ंक्शन चर का उपयोग करने के लिए कुछ समय बिताना पड़ा

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

7
इसके अलावा अगर आप सब कुछ नस्टेड नहीं करना चाहते हैं। धन्यवाद!
माइकल ओजेरान्सकी

2
जब यह निश्चित रूप से काम करता है, तो ध्यान दें कि ज्यादातर मामलों में आप चाहते हैं कि अजेय के जवाब में प्रदर्शित किए गए async विकल्प को प्रदर्शित किया जाए।
ट्रिफोर्ससी

1
const generateToken = (): Promise<string> => new Promise(resolve => randomBytes(48, (err, buffer) => resolve(buffer.toString('hex'))));
यंत्राब

1
@ स्पष्टता से आप बता सकते हैं कि आप आमतौर पर एसक्यूएन विकल्प क्यों चाहते हैं?
थोमस

2
@thomas रैंडम डेटा हार्डवेयर के आधार पर गणना करने में थोड़ा समय ले सकता है। कुछ मामलों में अगर कंप्यूटर रैंडम डेटा से बाहर निकलता है तो यह बस उसी जगह पर कुछ लौटाएगा। हालाँकि अन्य मामलों में यह संभव है कि कंप्यूटर रैंडम डेटा की वापसी में देरी करेगा (जो कि वास्तव में आप क्या चाहते हैं) जिसके परिणामस्वरूप धीमी कॉल होती है।
Triforcey

80

0. नैनोइड थर्ड पार्टी लाइब्रेरी का उपयोग करना [NEW!]

जावास्क्रिप्ट के लिए एक छोटा, सुरक्षित, यूआरएल-अनुकूल, अद्वितीय स्ट्रिंग आईडी जनरेटर

https://github.com/ai/nanoid

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


1. बेस 64 URL और फाइलनाम सुरक्षित वर्णमाला के साथ एन्कोडिंग

RCF 4648 का पेज 7 बताता है कि URL सुरक्षा के साथ बेस 64 में कैसे एनकोड करना है। आप नौकरी करने के लिए बेस 64url जैसी मौजूदा लाइब्रेरी का उपयोग कर सकते हैं ।

समारोह होगा:

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.

2
@Lexynux Solution 1 (URL और फाइलनाम सुरक्षित वर्णमाला के साथ बेस 64 एनकोडिंग) क्योंकि यह सुरक्षा की दृष्टि से सबसे मजबूत समाधान है। यह समाधान केवल कुंजी को एन्कोड करता है और कुंजी उत्पादन प्रक्रिया में हस्तक्षेप नहीं करता है।
यवेस एम।

आपके समर्थन के लिए धन्यवाद। क्या आपके पास समुदाय के साथ साझा करने के लिए कोई काम करने का उदाहरण है? इसका स्वागत किया जाएगा?
अलेक्सांटुरियो

6
खबरदार है कि उत्पन्न यादृच्छिक स्ट्रिंग समान रूप से वितरित नहीं है। यह दिखाने के लिए एक आसान उदाहरण है, कि लंबाई 255 के एक चरित्र सेट और 1 की एक स्ट्रिंग लंबाई के लिए, पहले चरित्र के दिखने की संभावना दोगुनी है।
फ्लोरियन वेंडेलबोर्न

@Dodekeract हाँ, आप समाधान 2 के बारे में बात कर रहे हैं .. यही कारण है कि समाधान 1 रास्ता अधिक मजबूत है
यवेस एम।

मैंने अपनी प्रतिक्रिया github.com/ai/nanoid
Yves M.

13

अप-टू-डेट सही तरीका यह करने के लिए एसिंक्रोनस रूप से ES 2016 मानकों का उपयोग करते हुए async और प्रतीक्षित (नोड 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 में बॉक्स से बाहर काम करता है


मैंने इस उदाहरण को अद्यतन किया है जिसमें नामांकित मापदंडों को पारित करने की नई विधि को यहाँ वर्णित किया गया है: 2ality.com/2011/11/keyword-parameters.html
real_ate

7

रैंडम URL और फ़ाइल नाम स्ट्रिंग सुरक्षित (1 लाइनर)

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

यह सादगी में एक अद्भुत जवाब है! बस इस बात से अवगत रहें कि यह ईवेंट लूप को एक अनिश्चित तरीके से स्टाल कर सकता है (केवल प्रासंगिक अगर इसका उपयोग अक्सर किया जाता है, कुछ हद तक लोड-समय-संवेदनशील प्रणाली में)। अन्यथा, एक ही काम करें, लेकिन randomBytes के async संस्करण का उपयोग करें। देखें नोडज्स.ओआरपी
एलेक थिलेनियस

6

चेक आउट:

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

अच्छा! पूरी तरह से कम समाधान। बहुत अच्छा होगा यदि आप "लेंथ" का नाम बदलकर "वांछितलॉग" कर दें और इसे इस्तेमाल करने से पहले एक मूल्य के साथ शुरू करें :)
फ्लोरियन ब्लम

किसी को भी आश्चर्य हो, ceilऔर sliceकॉल वांछित लंबाई के लिए आवश्यक हैं जो विषम हैं। यहां तक ​​कि लंबाई के लिए, वे कुछ भी नहीं बदलते हैं।
सेठ

6

Async / प्रतीक्षा और प्रॉमिस के साथ

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

के समान कुछ उत्पन्न करता है VjocVHdFiz5vGHnlnwqJKN0NdeHcz8eM


4

पर देखो real_atesES2016 तरह से, यह अधिक सही है।

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

@Jeffpowrs दरअसल, जावास्क्रिप्ट अपग्रेड हो रहा है :) लुकअप प्रॉमिस एंड जेनरेटर्स!
के - एसओ में विषाक्तता बढ़ रही है।

प्रतीक्षा का प्रयास करें, एक और ECMA7 वादा हैंडलर
जैन

मुझे लगता है कि आपको ES 2016 को इस पर पहला उदाहरण बनाना चाहिए क्योंकि यह ज्यादातर मामलों में "इसे करने का सही तरीका" की ओर बढ़ रहा है
real_ate

मैंने अपने स्वयं के नीचे एक उत्तर जोड़ा, जो नोड के लिए विशिष्ट था (आयात के बजाय आवश्यकता का उपयोग करके)। क्या कोई विशेष कारण था कि आप आयात का उपयोग क्यों कर रहे हैं? क्या आपके पास बेबल चल रहा है?
real_ate

@real_ate वास्तव में मैं था, जब तक आयात आधिकारिक रूप से समर्थित नहीं है, तब तक मैं कॉमनजेस का उपयोग करने के लिए वापस आ गया हूं।
के - एसओ में विषाक्तता बढ़ रही है।


2

एनपीएम मॉड्यूल कहीं भी विभिन्न प्रकार के स्ट्रिंग आईडी / कोड उत्पन्न करने के लिए लचीला एपीआई प्रदान करता है।

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()यादृच्छिक उत्पन्न करने के लिए उपयोग करता है।


1

यहां @Yves M. के उत्तर के ऊपर एक async संस्करण लिया गया है

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 सुरक्षित है और इसमें बेस 64 एन्कोडिंग है! यह ऊपर से 2 उत्तरों का संयोजन है।

const randomToken = () => {
    crypto.randomBytes(64).toString('base64').replace(/\//g,'_').replace(/\+/g,'-');
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.