नोड.जेएस के साथ एक सुरक्षित रीस्ट एपीआई कैसे लागू करें


204

मैं नोड.जेएस, एक्सप्रेस और मोंगोडब के साथ एक रीस्ट एपीआई की योजना बनाना शुरू करता हूं। एपीआई एक वेबसाइट (सार्वजनिक और निजी क्षेत्र) और शायद बाद में एक मोबाइल ऐप के लिए डेटा प्रदान करता है। सीमांत को AngularJS के साथ विकसित किया जाएगा।

कुछ दिनों के लिए मैंने REST API को सुरक्षित करने के बारे में बहुत कुछ पढ़ा, लेकिन मुझे अंतिम समाधान नहीं मिला। जहां तक ​​मैं समझता हूं कि मूल सुरक्षा प्रदान करने के लिए HTTPS का उपयोग करना है। लेकिन मैं उस उपयोग के मामलों में एपीआई की सुरक्षा कैसे कर सकता हूं:

  • वेबसाइट / ऐप के केवल आगंतुकों / उपयोगकर्ताओं को वेबसाइट / ऐप के सार्वजनिक क्षेत्र के लिए डेटा प्राप्त करने की अनुमति है

  • केवल प्रमाणित और अधिकृत उपयोगकर्ताओं को निजी क्षेत्र के लिए डेटा प्राप्त करने की अनुमति है (और केवल डेटा, जहां उपयोगकर्ता ने अनुमति दी है)

फिलहाल मुझे लगता है कि केवल सक्रिय सत्र वाले उपयोगकर्ताओं को एपीआई का उपयोग करने की अनुमति है। उपयोगकर्ताओं को अधिकृत करने के लिए मैं पासपोर्ट का उपयोग करूंगा और अनुमति के लिए मुझे अपने लिए कुछ लागू करने की आवश्यकता होगी। सभी HTTPS के शीर्ष पर।

क्या कोई व्यक्ति कुछ सर्वोत्तम अभ्यास या अनुभव प्रदान कर सकता है? क्या मेरी "वास्तुकला" में कोई कमी है?


2
मैं अनुमान लगा रहा हूं कि एपीआई केवल आपके द्वारा प्रदान किए गए दृश्यपटल से उपयोग किया जाना है? उस स्थिति में, उपयोगकर्ता को यह सुनिश्चित करने के लिए सत्र का उपयोग करना एक अच्छा समाधान लगता है। अनुमतियों के लिए, आप नोड-रोल्स पर एक नज़र डाल सकते हैं ।
रॉबर्टबेल्प

2
इसके लिए आपने आखिर क्या किया? कोई भी बॉयलर प्लेट कोड (सर्वर / मोबाइल ऐप क्लाइंट) जिसे आप साझा कर सकते हैं?
मोर्टिजा शाहरीरी निया

जवाबों:


175

मैंने वही समस्या बताई है जिसका आप वर्णन करते हैं। मैं जिस वेब साइट का निर्माण कर रहा हूं, उसे मोबाइल फोन और ब्राउज़र से एक्सेस किया जा सकता है, इसलिए मुझे उपयोगकर्ताओं को साइनअप करने, लॉगिन करने और कुछ विशिष्ट कार्यों को करने के लिए एक एपीआई की आवश्यकता है। इसके अलावा, मुझे स्केलेबिलिटी, विभिन्न प्रक्रियाओं / मशीनों पर चलने वाले समान कोड का समर्थन करने की आवश्यकता है।

क्योंकि उपयोगकर्ता संसाधनों को सृजित कर सकते हैं (उर्फ POST / PUT क्रियाएँ) आपको अपने एपीआई को सुरक्षित करने की आवश्यकता है। आप ओउथ का उपयोग कर सकते हैं या आप अपना स्वयं का समाधान बना सकते हैं, लेकिन ध्यान रखें कि पासवर्ड को खोजने के लिए वास्तव में आसान होने पर सभी समाधान टूट सकते हैं। मूल विचार उपयोगकर्ताओं को उपयोगकर्ता नाम, पासवर्ड और एक टोकन का उपयोग करके प्रमाणित करने का है, एपिटोकन। यह एपिटोकैन नोड- यूआईडी का उपयोग करके उत्पन्न किया जा सकता है और पासवर्ड को pbkdf2 का उपयोग करके हैशेड किया जा सकता है

फिर, आपको सत्र को कहीं और सहेजने की आवश्यकता है। यदि आप इसे एक सादे ऑब्जेक्ट में मेमोरी में सहेजते हैं, यदि आप सर्वर को मारते हैं और इसे फिर से रिबूट करते हैं तो सत्र नष्ट हो जाएगा। इसके अलावा, यह स्केलेबल नहीं है। यदि आप मशीनों के बीच संतुलन लोड करने के लिए हैप्रोक्सी का उपयोग करते हैं या यदि आप केवल श्रमिकों का उपयोग करते हैं, तो यह सत्र स्थिति एक ही प्रक्रिया में संग्रहीत की जाएगी ताकि यदि उसी उपयोगकर्ता को किसी अन्य प्रक्रिया / मशीन पर पुनर्निर्देशित किया जाए तो उसे फिर से प्रमाणित करने की आवश्यकता होगी। इसलिए आपको सत्र को एक सामान्य स्थान पर संग्रहीत करने की आवश्यकता है। यह आमतौर पर रेडिस का उपयोग करके किया जाता है।

जब उपयोगकर्ता प्रमाणित हो जाता है (उपयोगकर्ता नाम + पासवर्ड + एपिटोकेन) सत्र के लिए एक और टोकन उत्पन्न करता है, तो उर्फ ​​accesstoken। फिर से, नोड-यूयूआईडी के साथ। उपयोगकर्ता को accesstoken और userid को भेजें। उपयोगकर्ता (कुंजी) और accesstoken (मान) के साथ रेडिस में संग्रहीत किया जाता है और समय समाप्त होता है, जैसे 1 एच।

अब, हर बार उपयोगकर्ता बाकी एपीआई का उपयोग करके किसी भी ऑपरेशन को करता है, इसके लिए उपयोगकर्ता को और accesstoken को भेजना होगा।

यदि आप उपयोगकर्ताओं को शेष एपीआई का उपयोग करके साइनअप करने की अनुमति देते हैं, तो आपको एक व्यवस्थापक एपिटोकेन के साथ एक व्यवस्थापक खाता बनाने और उन्हें मोबाइल ऐप में संग्रहीत करने की आवश्यकता होगी (उपयोगकर्ता नाम + पासवर्ड + एपिटोकेन एन्क्रिप्ट करें) क्योंकि नए उपयोगकर्ताओं के पास एपिटोकन नहीं होगा वे साइन अप करते हैं।

वेब भी इस एपीआई का उपयोग करता है, लेकिन आपको एपिटोकेंस का उपयोग करने की आवश्यकता नहीं है। आप रेडिस स्टोर के साथ एक्सप्रेस का उपयोग कर सकते हैं या ऊपर वर्णित एक ही तकनीक का उपयोग कर सकते हैं लेकिन एपिटोकन चेक को दरकिनार करके उपयोगकर्ता को कुकी में उपयोगकर्ता + एक्सीस्टोकोकन वापस कर सकते हैं।

यदि आपके पास निजी क्षेत्र हैं, तो उपयोगकर्ता को प्रमाणित होने पर अनुमत उपयोगकर्ताओं के साथ तुलना करें। आप उपयोगकर्ताओं को भूमिकाएँ भी लागू कर सकते हैं।

सारांश:

अनुक्रम आरेख

एपिटोकेन के बिना एक विकल्प HTTPS का उपयोग करना और प्राधिकरण हेडर में उपयोगकर्ता नाम और पासवर्ड भेजना और उपयोगकर्ता को रेडिस में कैश करना होगा।


1
मैं मोंगोडब का भी उपयोग करता हूं, लेकिन यदि आप सत्र (एसेसस्टोकन) को रेडिस (परमाणु संचालन का उपयोग करें) का उपयोग करके सहेजना बहुत आसान है। एपिटोकेन सर्वर में उत्पन्न होता है जब उपयोगकर्ता खाता बनाता है और इसे उपयोगकर्ता को वापस भेज देता है। फिर, जब उपयोगकर्ता प्रमाणित करना चाहता है तो उसे उपयोगकर्ता नाम + पासवर्ड + एपिटोकेन (उन्हें http बॉडी में डालें) भेजना होगा। ध्यान रखें कि HTTP शरीर को एन्क्रिप्ट नहीं करता है इसलिए पासवर्ड और एपिटोकेन को सूँघा जा सकता है। अगर यह आपके लिए चिंता का विषय है तो HTTPS का उपयोग करें।
गेब्रियल ललामास

1
एक का उपयोग करने पर क्या बात है apitoken? क्या यह एक "माध्यमिक" पासवर्ड है?
साल्वेटेरलैब

2
@ TheBronx एपिटोकेन में 2 उपयोग के मामले हैं: 1) एपिटोकन के साथ आप अपने सिस्टम में उपयोगकर्ताओं की पहुंच को नियंत्रित कर सकते हैं और आप प्रत्येक उपयोगकर्ता के आंकड़ों की निगरानी और निर्माण कर सकते हैं। 2) यह एक अतिरिक्त सुरक्षा उपाय है, एक "माध्यमिक" पासवर्ड।
गेब्रियल लामास

1
सफल प्रमाणीकरण के बाद आपको उपयोगकर्ता आईडी को बार-बार क्यों भेजना चाहिए। टोकन केवल वही होना चाहिए जो आपको एपीआई कॉल करने के लिए चाहिए।
एक्सल नेपोलिटानो

1
टोकन की आइडिया - उपयोगकर्ता गतिविधि को ट्रैक करने के लिए इसका दुरुपयोग करने के साथ -, यह है कि एक उपयोगकर्ता को आदर्श रूप से किसी एप्लिकेशन का उपयोग करने के लिए किसी उपयोगकर्ता नाम और पासवर्ड की आवश्यकता नहीं है: टोकन अद्वितीय एक्सेस कुंजी है। यह उपयोगकर्ताओं को किसी भी समय किसी भी ऐप को प्रभावित करने की अनुमति देता है केवल ऐप को प्रभावित करता है लेकिन उपयोगकर्ता खाते को नहीं। एक webservice के लिए एक टोकन काफी अनहेल्दी है - यही कारण है कि एक सत्र के लिए एक प्रारंभिक लॉगिन वह जगह है जहां उपयोगकर्ता को वह टोकन मिलता है - "नियमित" क्लाइंट एब के लिए, एक टोकन कोई समस्या नहीं है: इसे एक बार दर्ज करें और लगभग एक बार किया। ;)
एक्सल नेपोलिटानो

22

स्वीकार किए गए उत्तर के अनुसार, इस प्रश्न के लिए एक संरचनात्मक समाधान के रूप में मैं इस कोड का योगदान देना चाहूंगा। (आप बहुत आसानी से इसे अनुकूलित कर सकते हैं)।

// ------------------------------------------------------
// server.js 

// .......................................................
// requires
var fs = require('fs');
var express = require('express'); 
var myBusinessLogic = require('../businessLogic/businessLogic.js');

// .......................................................
// security options

/*
1. Generate a self-signed certificate-key pair
openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out certificate.pem

2. Import them to a keystore (some programs use a keystore)
keytool -importcert -file certificate.pem -keystore my.keystore
*/

var securityOptions = {
    key: fs.readFileSync('key.pem'),
    cert: fs.readFileSync('certificate.pem'),
    requestCert: true
};

// .......................................................
// create the secure server (HTTPS)

var app = express();
var secureServer = require('https').createServer(securityOptions, app);

// ------------------------------------------------------
// helper functions for auth

// .............................................
// true if req == GET /login 

function isGETLogin (req) {
    if (req.path != "/login") { return false; }
    if ( req.method != "GET" ) { return false; }
    return true;
} // ()

// .............................................
// your auth policy  here:
// true if req does have permissions
// (you may check here permissions and roles 
//  allowed to access the REST action depending
//  on the URI being accessed)

function reqHasPermission (req) {
    // decode req.accessToken, extract 
    // supposed fields there: userId:roleId:expiryTime
    // and check them

    // for the moment we do a very rigorous check
    if (req.headers.accessToken != "you-are-welcome") {
        return false;
    }
    return true;
} // ()

// ------------------------------------------------------
// install a function to transparently perform the auth check
// of incoming request, BEFORE they are actually invoked

app.use (function(req, res, next) {
    if (! isGETLogin (req) ) {
        if (! reqHasPermission (req) ){
            res.writeHead(401);  // unauthorized
            res.end();
            return; // don't call next()
        }
    } else {
        console.log (" * is a login request ");
    }
    next(); // continue processing the request
});

// ------------------------------------------------------
// copy everything in the req body to req.body

app.use (function(req, res, next) {
    var data='';
    req.setEncoding('utf8');
    req.on('data', function(chunk) { 
       data += chunk;
    });
    req.on('end', function() {
        req.body = data;
        next(); 
    });
});

// ------------------------------------------------------
// REST requests
// ------------------------------------------------------

// .......................................................
// authenticating method
// GET /login?user=xxx&password=yyy

app.get('/login', function(req, res){
    var user = req.query.user;
    var password = req.query.password;

    // rigorous auth check of user-passwrod
    if (user != "foobar" || password != "1234") {
        res.writeHead(403);  // forbidden
    } else {
        // OK: create an access token with fields user, role and expiry time, hash it
        // and put it on a response header field
        res.setHeader ('accessToken', "you-are-welcome");
        res.writeHead(200); 
    }
    res.end();
});

// .......................................................
// "regular" methods (just an example)
// newBook()
// PUT /book

app.put('/book', function (req,res){
    var bookData = JSON.parse (req.body);

    myBusinessLogic.newBook(bookData, function (err) {
        if (err) {
            res.writeHead(409);
            res.end();
            return;
        }
        // no error:
        res.writeHead(200);
        res.end();
    });
});

// .......................................................
// "main()"

secureServer.listen (8081);

इस सर्वर को कर्ल के साथ परीक्षण किया जा सकता है:

echo "----   first: do login "
curl -v "https://localhost:8081/login?user=foobar&password=1234" --cacert certificate.pem

# now, in a real case, you should copy the accessToken received before, in the following request

echo "----  new book"
curl -X POST  -d '{"id": "12341324", "author": "Herman Melville", "title": "Moby-Dick"}' "https://localhost:8081/book" --cacert certificate.pem --header "accessToken: you-are-welcome" 

इस नमूने के लिए धन्यवाद, यह बहुत उपयोगी है, हालांकि मैं इसका पालन करने की कोशिश करता हूं, और जब मैं इसे यह कहते हुए लॉगिन करने के लिए जोड़ता हूं: कर्ल: (51) एसएसएल: प्रमाणपत्र विषय नाम 'xxxx' लक्ष्य होस्ट नाम 'xxx.net' से मेल नहीं खाता है। मैंने हार्डकॉस्टेड मेरे / etc / होस्ट्स को अनुमति देने के लिए https उसी मशीन पर कनेक्ट कर रहा है
mastervv

11

मैंने अभी एक नमूना एप्लिकेशन समाप्त किया है जो एक बहुत ही मूल, लेकिन स्पष्ट तरीके से करता है। यह उपयोगकर्ताओं को संग्रहीत करने के लिए मोंगोडब के साथ मैंगोज़ का उपयोग करता है और मौखिक प्रबंधन के लिए पासपोर्ट।

https://github.com/Khelldar/Angular-Express-Train-Seed


7
आप एपीआई सुरक्षित करने के लिए कुकी का उपयोग कर रहे हैं। मुझे नहीं लगता कि यह सही है।
विंस युआन

9

SO पर यहाँ REST के कई पैटर्न के बारे में कई प्रश्न हैं। ये आपके प्रश्न के लिए सबसे अधिक प्रासंगिक हैं:

मूल रूप से आपको API कुंजियों का उपयोग करने के बीच चयन करने की आवश्यकता है (कम से कम सुरक्षित रूप से कुंजी एक अनधिकृत उपयोगकर्ता द्वारा खोजी जा सकती है), एक ऐप कुंजी और टोकन कॉम्बो (मध्यम), या एक पूर्ण OAuth कार्यान्वयन (सबसे सुरक्षित)।


मैंने oauth 1.0 और oauth 2.0 के बारे में बहुत कुछ पढ़ा है और दोनों संस्करण बहुत सुरक्षित नहीं हैं। विकिपीडिया ने लिखा है कि oauth 1.0 में कुछ सुरक्षा लीक हैं। इसके अलावा, मैंने एक लेख में पाया कि कोर डेवलपर में से एक के बारे में टीम को छोड़ दो oauth 2.0 असुरक्षित है।
tschiela

12
@tschiela आपको अपने द्वारा यहां बताई गई किसी भी चीज़ का संदर्भ जोड़ना चाहिए।
मिकमेकाना जूल

3

यदि आप अपने एप्लिकेशन को सुरक्षित करना चाहते हैं, तो आपको निश्चित रूप से HTTP के बजाय HTTPS का उपयोग करके शुरू करना चाहिए , यह आपके और उपयोगकर्ताओं के बीच एक सुरक्षित चैनल बनाना सुनिश्चित करता है जो उपयोगकर्ताओं को भेजे गए डेटा को वापस भेजने से रोक देगा और उपयोगकर्ताओं को डेटा रखने में मदद करेगा आदान-प्रदान गोपनीय।

RESTful API को सुरक्षित करने के लिए आप JWTs (JSON वेब कैम) का उपयोग कर सकते हैं , सर्वर-साइड सत्रों की तुलना में इसके कई लाभ हैं, लाभ मुख्य रूप से हैं:

1- अधिक स्केलेबल, क्योंकि आपके एपीआई सर्वर को प्रत्येक उपयोगकर्ता के लिए सत्र नहीं बनाए रखने होंगे (जो आपके कई सत्र होने पर बड़ा बोझ हो सकता है)

2- JWT स्वयं सम्‍मिलित हैं और उनके दावे हैं जो उदाहरण के लिए उपयोगकर्ता की भूमिका को परिभाषित करते हैं और वह उस तिथि और समाप्ति तिथि पर पहुंच सकते हैं और जारी कर सकते हैं (जिसके बाद JWT मान्य नहीं होगा)

3- लोड-बैलेन्सर्स को हैंडल करने में आसान और अगर आपके पास कई एपीआई सर्वर हैं, तो आपको सत्र डेटा साझा करने की आवश्यकता नहीं होगी और न ही सत्र को उसी सर्वर पर रूट करने के लिए सर्वर कॉन्फ़िगर करें, जब भी JWT के साथ किसी भी सर्वर को हिट करने का अनुरोध किया जाता है, तो इसे प्रमाणित किया जा सकता है & अधिकार दिया गया

4- आपके डीबी पर कम दबाव और साथ ही आपको प्रत्येक अनुरोध के लिए सत्र आईडी और डेटा को लगातार संग्रहीत और पुनर्प्राप्त नहीं करना होगा

5- JWT के साथ छेड़छाड़ नहीं की जा सकती है यदि आप JWT पर हस्ताक्षर करने के लिए एक मजबूत कुंजी का उपयोग करते हैं, तो आप JWT में उन दावों पर भरोसा कर सकते हैं जो उपयोगकर्ता सत्र की जांच किए बिना अनुरोध के साथ भेजे गए हैं और वह अधिकृत है या नहीं। , आप बस JWT की जांच कर सकते हैं और फिर आप यह जानने के लिए पूरी तरह तैयार हैं कि यह उपयोगकर्ता कौन और क्या कर सकता है।

कई पुस्तकालय अधिकांश प्रोग्रामिंग भाषाओं में JWTs बनाने और मान्य करने के लिए आसान तरीके प्रदान करते हैं, उदाहरण के लिए: नोड में। सबसे लोकप्रिय में से एक है jsonwebtoken

चूंकि REST API आमतौर पर सर्वर को स्टेटलेस रखने का लक्ष्य रखते हैं, इसलिए JWT उस कॉन्सेप्ट के साथ अधिक संगत होते हैं क्योंकि प्रत्येक अनुरोध को प्राधिकरण टोकन के साथ भेजा जाता है जो सेल्फ (JWT) सर्वर के बिना सेशन की तुलना में यूजर सेशन का ट्रैक रखने के लिए होता है जो इसे बनाते हैं सर्वर स्टेटफुल है ताकि यह उपयोगकर्ता और उसकी भूमिका को याद रखे, हालांकि, सत्रों का भी व्यापक रूप से उपयोग किया जाता है और उनके पेशेवरों के पास हैं, जिन्हें आप चाहें तो खोज सकते हैं।

एक महत्वपूर्ण बात यह है कि आपको HTTPS का उपयोग करके क्लाइंट को JWT को सुरक्षित रूप से डिलीवर करना होगा और इसे सुरक्षित स्थान पर सहेजना होगा (उदाहरण के लिए स्थानीय भंडारण में)।

आप इस लिंक से JWTs के बारे में अधिक जान सकते हैं


1
मुझे आपका उत्तर पसंद है जो इस पुराने प्रश्न से सबसे अच्छा अपडेट लगता है। मैंने अपने आप से उसी विषय पर एक अन्य प्रश्न पूछा है और आप भी सहायक हो सकते हैं। => stackoverflow.com/questions/58076644/…
pbonnefoi

धन्यवाद, खुशी है कि मैं मदद कर सकता हूं, मैं आपके प्रश्न के लिए एक उत्तर पोस्ट कर रहा हूं
अहमद एल्कौसी

2

यदि आप अपने वेबप्लिकेशन का पूरी तरह से लॉक डाउन एरिया चाहते हैं, जिसे केवल आपकी कंपनी के एडमिनिस्ट्रेटर ही एक्सेस कर सकते हैं, तो एसएसएल ऑथोराइजेशन शायद आपके लिए। यह बीमा करेगा कि कोई भी तब तक सर्वर इंस्टेंस से संबंध नहीं बना सकता जब तक कि उनके पास उनके ब्राउज़र में अधिकृत प्रमाणपत्र स्थापित न हो। पिछले हफ्ते मैंने सर्वर को सेटअप करने के तरीके पर एक लेख लिखा था: अनुच्छेद

यह उन सबसे सुरक्षित सेटअपों में से एक है जो आप पाएंगे कि इसमें कोई उपयोगकर्ता नाम / पासवर्ड शामिल नहीं हैं, इसलिए कोई भी पहुंच प्राप्त नहीं कर सकता है जब तक कि आपके उपयोगकर्ता में से कोई एक संभावित हैकर को महत्वपूर्ण फाइलें नहीं सौंपता है।


अच्छा लेख। लेकिन निजी क्षेत्र उपयोगकर्ताओं के लिए है।
tschiela

धन्यवाद - सही है, तो आपको दूसरे समाधान के लिए जाना चाहिए, प्रमाण पत्र वितरित करना एक दर्द होगा।
एक्जक्का
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.