उल्का में सुरक्षा के बारे में और न केवल (भाग 2)

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

loginToken


प्राधिकरण के बाद, क्लाइंट को वर्तमान उपयोगकर्ता को अधिकृत करते हुए एक अस्थायी टोकन प्राप्त होता है, जिसे स्थानीयस्टोरेज में संग्रहीत किया जाता है:
> localStorage.getItem("Meteor.loginToken") "eEg4T3fNPGLns7MfY" 

कड़ाई से बोलते हुए, इसे Meteor._locaStorage ऑब्जेक्ट में संग्रहीत किया जाता है, जो कि इसका समर्थन करने वाले ब्राउज़रों के लिए window.localStorage के लिए एक आवरण है।
आप इस टोकन को अकाउंट ऑब्जेक्ट के माध्यम से भी देख सकते हैं:
 Accounts._storedLoginToken() 

Meteor.users संग्रह में सर्वर पर एक ही टोकन संग्रहीत है:
 > Meteor.user().services.resume { "loginTokens": [ { "token":"DXC3BqekpPy97fmYs", "when":"2014-01-31T10:53:54.347Z" } ] } 

बेशक, ब्राउज़र कंसोल में, यह फ़ील्ड केवल तभी उपलब्ध है जब यह स्पष्ट रूप से प्रकाशित हो।

कोई भी ब्राउज़र जिसमें टोकन + उपयोगकर्ता आईडी की एक जोड़ी है, को अधिकृत माना जाता है। इसे सत्यापित करने के लिए, आप ब्राउज़र में लॉग इन कर सकते हैं और वर्तमान लॉगिन को प्राप्त कर सकते हैं।
 localStorage.getItem("Meteor.loginToken"); localStorage.getItem("Meteor.userId"); 

फिर उन्हें दूसरे ब्राउज़र में स्थापित करें:
 localStorage.setItem("Meteor.loginToken", "'+loginToken+'"); localStorage.setItem("Meteor.userId", "'+userId+'"); 

और कुछ क्षणों के बाद, ब्राउज़र सत्र अधिकृत हो जाएगा।

टोकन लाइफटाइम

टोकन तब तक मौजूद रहता है जब तक कि उपयोगकर्ता लॉग आउट नहीं करता है या पैरामीटर की समय सीमा समाप्त हो जाती है (डिफ़ॉल्ट 60 दिन है):
 Accounts.config({loginExpirationInDays: 60}) 


एक संग्रह को बदलने के लिए ग्राहक विशेषाधिकार सीमित - अनुमति / नियमों से इनकार


यदि हम सेवाओं को उप-परिवर्तन करने का प्रयास करते हैं, तो हम ब्राउज़र से ऐसा नहीं कर सकते हैं:
 > Meteor.users.update({ _id: Meteor.userId() }, {$set: { "services.test": "test" } }) undefined update failed: Access denied 

यह इस तथ्य के कारण होता है कि सर्वर पर इस दस्तावेज़ तक पहुंच की अनुमति / नियमों से सीमित है। आइए देखें कि यह तंत्र खातों के आधार पैकेज स्रोतों में कैसे लागू किया जाता है:
 Meteor.users.allow({ // clients can modify the profile field of their own document, and // nothing else. update: function (userId, user, fields, modifier) { // make sure it is our record if (user._id !== userId) return false; // user can only modify the 'profile' field. sets to multiple // sub-keys (eg profile.foo and profile.bar) are merged into entry // in the fields list. if (fields.length !== 1 || fields[0] !== 'profile') return false; return true; }, fetch: ['_id'] // we only look at _id. }); 

यह कोड से देखा जा सकता है कि केवल दस्तावेज़ में परिवर्तन की अनुमति है जिसका उपयोगकर्ता वर्तमान उपयोगकर्ता से मेल खाता है, और आप केवल प्रोफ़ाइल उप-बदलाव में परिवर्तन कर सकते हैं। मेट पैरामीटर कहता है कि अनुमतियों की जांच करने के लिए संपूर्ण संशोधित दस्तावेज़ प्राप्त करना आवश्यक नहीं है (यह बड़ा हो सकता है), केवल एक _id फ़ील्ड जाँचने के लिए पर्याप्त है। चूंकि नियम की अनुमति केवल अद्यतन कार्रवाई के लिए घोषित की जाती है, ग्राहक के लिए परिचालन सम्मिलित करना और निकालना प्रतिबंधित है:
 > Meteor.users.insert({}) "qs8HbcSDjgbgb3vgS" insert failed: Access denied. No allow validators set on restricted collection for method 'insert'. 

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

Subdocument पहुँच अधिकार सत्यापित करना

अपडेट ऑपरेशन के साथ, सत्यापन विकल्प कुछ सीमित हैं। उदाहरण के लिए, यदि किसी उपखंड के क्षेत्र में लेखन को प्रतिबंधित करना आवश्यक है, उदाहरण के लिए, doc.field1, लेकिन इसे किसी अन्य फ़ील्ड में रखने की अनुमति देने के लिए, उदाहरण के लिए, हमारे संग्रह परीक्षण के doc.field2, यह सिर्फ काम नहीं करेगा। आइए देखते हैं कि इस मामले में नियम के लिए कौन से पैरामीटर पारित किए गए हैं जो सर्वर के लिए अनुमति और इनपुट इनपुट मापदंडों के नियमों को अस्वीकार करते हैं:
 Test.allow({ update: function (userId, document, fields, modifier) { console.log('Test.allow(): userId:', userId, '; document:', document, '; fields:', fields, '; modifier:' , modifier); return true; } }); Test.deny({ update: function (userId, document, fields, modifier) { console.log('Test.deny(): userId:', userId, '; document:', document, '; fields:', fields, '; modifier:' , modifier); return false; } }); 

और हम doc.field1 फ़ील्ड के लिए अपडेट ऑपरेशन करेंगे, जिनमें से एक दस्तावेज़ के _id को पहले से पहचाना होगा (यह सुनिश्चित करें कि हमारे उदाहरण कोड में प्रक्षेपण = {} चर सेट करके परीक्षण संग्रह में आवश्यक फ़ील्ड प्रकाशित किए गए हैं, अन्यथा परिणाम दिखाई नहीं देगा):
 > Test.findOne({_id: "FG7FaQqYgB7Rs9RDy"}) Object {_id: "FG7FaQqYgB7Rs9RDy", name: "First", value: 1} > Test.update({_id:"FG7FaQqYgB7Rs9RDy"}, { $set: { "doc.field1": "value1" } } ) undefined > Test.findOne({_id: "FG7FaQqYgB7Rs9RDy"}) Object {_id: "FG7FaQqYgB7Rs9RDy", name: "First", value: 1, doc: Object} > Test.findOne({_id: "FG7FaQqYgB7Rs9RDy"}).doc.field1 "value1" 

सर्वर लॉग प्रदर्शित करेगा:
 I20140131-13:31:27.582(4)? Test.deny(): userId: kL7Fkuk29ci4vz8q4 ; document: { _id: 'FG7FaQqYgB7Rs9RDy', name: 'First', value: 1 } ; fields: [ 'doc' ] ; modifier: { '$set': { 'doc.field1': 'value1' } } I20140131-13:31:27.582(4)? Test.allow(): userId: kL7Fkuk29ci4vz8q4 ; document: { _id: 'FG7FaQqYgB7Rs9RDy', name: 'First', value: 1 } ; fields: [ 'doc' ] ; modifier: { '$set': { 'doc.field1': 'value1' } } 

फ़ील्ड पैरामीटर में, केवल शीर्ष-सबसे स्तर के क्षेत्रों का निष्क्रिय पास किया जाता है, अर्थात, इसके आधार पर, आप डॉक्स फ़ील्ड (और इसके सभी उप-विभाजनों) तक पहुंच अधिकार निर्धारित कर सकते हैं, लेकिन इस सरणी के आधार पर doc.field1 और doc.field फ़ील्ड के लिए अलग-अलग अधिकार लागू करना असंभव है। ऐसा करने के लिए, आप संशोधक पैरामीटर का उपयोग कर सकते हैं, जिसमें MongoDb ऑपरेशन वाली एक वस्तु पारित हो जाती है, और ऑपरेशन का पूरा विश्लेषण नहीं करने के लिए, केवल कुछ प्रकार के हार्ड प्रारूप की अनुमति देते हैं और किसी भी तरह से इसके अन्य विकल्पों को निषिद्ध करते हैं:
 Test.allow({ update: function (userId, user, fields, modifier) { console.log('Test.allow(): userId:', userId, '; document:', document, '; fields:', fields, '; modifier:' , modifier); var setData = modifier["$set"]; return setData && Object.keys(setData).length===1 && setData["doc.field1"]; } }); 

बेशक, अनुमति / अस्वीकार नियम तभी काम करते हैं जब असुरक्षित पैकेज परियोजना से हटा दिया जाता है। वैसे, क्लाइंट द्वारा किए गए सर्वर-साइड परिवर्तनों के लिए इन हैंडलर का भी उपयोग किया जा सकता है।

विश्वसनीय और अविश्वसनीय कोड


अब तक, हमने इसके पहचानकर्ता द्वारा रिकॉर्ड को संशोधित किया है। तथ्य यह है कि क्लाइंट अपडेट ऑपरेशन नहीं कर सकता है, उदाहरण के लिए अनुरोध चयनकर्ता में कुछ और दर्शाता है:
 Test.update({ value: 1 }, { $set: { "doc.field1": "value1" } } ) Error: Not permitted. Untrusted code may only update documents by ID. [403] 

यह इस तथ्य के कारण है कि उल्का विश्वसनीय और अविश्वसनीय कोड को अलग करता है। कोड जिसे सर्वर पर निष्पादित किया जाता है, जिसमें क्लाइंट द्वारा बुलाए गए सर्वर के तरीकों को भी विश्वसनीय माना जाता है। अनट्रस्टेड - कोड जिसे ब्राउज़र में क्लाइंट साइड पर निष्पादित किया जाता है।
अविश्वसनीय कोड को दस्तावेज़ को केवल एक बार संशोधित करने की अनुमति है, दस्तावेज़ के _id को दर्शाता है और अनुमति / इनकार नियमों की जांच करता है। इसके अलावा, यह अपग्रेड ऑपरेशन (यदि यह अनुपस्थित है तो किसी दस्तावेज़ को सम्मिलित करना) की अनुमति नहीं देता है। उसी तरह से हटाए गए ऑपरेशन को केवल एक ही दस्तावेज़ पर लागू किया जा सकता है, जिसमें उसका _id निर्दिष्ट है। अधिक विवरण के लिए docs.meteor.com/#update और docs.meteor.com/#remove प्रलेखन देखें

सर्वर के तरीके


डेटाबेस तक सीधे क्लाइंट पहुंच के विकल्प के रूप में, सर्वर-साइड विधियों का उपयोग किया जा सकता है। चूंकि सर्वर पर निष्पादित कोड विश्वसनीय माना जाता है, इसलिए क्लाइंट पर संबंधित संग्रह में परिवर्तन को रोकते हुए, सर्वर पर महत्वपूर्ण संचालन के तर्क को रखना संभव है। उदाहरण के लिए, सर्वर पर जोड़ें:
 Meteor.startup(function() { Meteor.methods({ testMethod: function(data) { console.log('testMethod(): data:', data); return 'testMethod finished (data:',data,')'; } }); }); 

और हम इसे ग्राहक की ओर से कॉल करेंगे, अंतिम पैरामीटर कॉलबैक को पास करते हुए, जब विधि पूरी हो जाएगी, तब कॉल किया जाएगा:
 > Meteor.call('testMethod', 'test data', function(err, result) {console.log(err, result);}) undefined undefined "testMethod finished (data:test data)" 


HTTPS और बल-एसएसएल पैकेज


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

 $ openssl genrsa -des3 -out localhost.key 1024 $ openssl req -new -key localhost.key -out localhost.csr Common Name (eg, YOUR name) :localhost $ openssl x509 -req -days 1024 -in localhost.csr -signkey localhost.key -out localhost.crt 

प्रमाण पत्र और कुंजी को / etc / nginx / ssl फ़ोल्डर में कॉपी करें
 $ mkdir /etc/nginx/ssl $ cp ./localhost.key /etc/nginx/ssl $ cp ./localhost.crt /etc/nginx/ssl 

Nginx कॉन्फ़िगरेशन

फ़ाइल बनाएं /etc/nginx/sites-available/meteor.conf (यदि Nginx को खरोंच से स्थापित किया गया है, तो आपको उसी निर्देशिका में स्थित डिफ़ॉल्ट फ़ाइल को हटाना या पुन: कॉन्फ़िगर करना होगा जिसमें समान पोर्ट पंजीकृत हैं):
 server { listen 80; server_name localhost; # $scheme will get the http protocol # and 301 is best practice for tablet, phone, desktop and seo # return 301 $scheme://example.com$request_uri; # We want to redirect people to the https site when they come to the http site. return 301 https://localhost$request_uri; } server { listen 443; server_name localhost; client_max_body_size 500M; access_log /var/log/nginx/meteorapp.access.log; error_log /var/log/nginx/meteorapp.error.log; location / { proxy_pass http://localhost:3000; proxy_set_header X-Real-IP $remote_addr; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } ssl on; ssl_certificate /etc/nginx/ssl/localhost.crt; ssl_certificate_key /etc/nginx/ssl/localhost.key; ssl_verify_depth 3; } 

लिंक बनाएं:
 ln -s /etc/nginx/sites-available/meteor.conf /etc/nginx/sites-enabled/meteor.conf 

फिर से शुरू करें:
 $ sudo service nginx restart 



ब्राउज़र-नीति, सामग्री सुरक्षा नीति और एक्स-फ़्रेम-विकल्प पैकेज


वास्तव में, ब्राउज़र-नीति के पीछे दो अन्य पैकेज छिपे हुए हैं, जिनमें से प्रत्येक को अलग से उपयोग किया जा सकता है, ब्राउज़र-नीति-सामग्री और ब्राउज़र-नीति-निर्धारण। इनमें से पहला सामग्री सुरक्षा नीति नियमों को परिभाषित करने के लिए एक इंटरफ़ेस प्रदान करता है जिसके द्वारा विभिन्न प्रकार के संसाधनों को लोड करने के लिए स्रोतों की एक सफेद सूची निर्दिष्ट की जाती है। दूसरा एक्स-फ्रेम-ओरिजिनल पैरामीटर है, जो फ्रेम या आइफ्रेम टैग के अंदर पेज को प्रदर्शित करने की अनुमति देता है, जो उस साइट के यूआरआई पर निर्भर करता है जो ऐसा करने की कोशिश कर रहा है (फिलहाल, एक्स-फ्रेम-ओरिजिन में स्रोत यूआरआई को निर्दिष्ट करना केवल फ़ायरफ़ॉक्स और आईई 8+ द्वारा समर्थित है)।
पैकेज को जोड़ने में एक डिफ़ॉल्ट नीति शामिल होती है, जबकि सामग्री को डाउनलोड करने की अनुमति केवल उसी साइट से होती है जो पृष्ठ पर ही है, XMLHTTPRequest अनुरोध और WebSocket कनेक्शन किसी भी साइट पर भेजे जा सकते हैं। इसके अलावा, जैसे कि eval () फ़ंक्शन अवरुद्ध हैं और एप्लिकेशन को फ्रेम में शामिल किया जा सकता है और iframe केवल उसी साइट से किया जाता है, जहां से इसे डाउनलोड किया गया था।

उसी समय, जब पृष्ठ लोड होता है, तो सर्वर प्रतिसाद शीर्ष लेख में निम्नलिखित पैरामीटर जोड़े जाते हैं:
 content-security-policy: default-src 'self'; script-src 'self' 'unsafe-inline'; connect-src * 'self'; img-src data: 'self'; style-src 'self' 'unsafe-inline'; x-frame-options: SAMEORIGIN 

और, हमारे उदाहरण में, बाहरी साइटों (Google और Facebook) से उपयोगकर्ता चित्र कंसोल में निम्न संदेश के साथ प्रदर्शित नहीं होंगे:
 Refused to load the image 'https://lh6.googleusercontent.com/-aCxpjiDMNcM/AAAAAAAAAAI/AAAAAAAAJMY/9hZytqLLZ6Q/photo.jpg' because it violates the following Content Security Policy directive: "img-src data: 'self'". 

बाहरी साइटों से छवियों को फिर से दिखाना शुरू करने के लिए, निम्न पंक्तियों को सर्वर में जोड़ें:
 Meteor.startup(function() { BrowserPolicy.content.allowImageOrigin("https://*.googleusercontent.com"); BrowserPolicy.content.allowImageOrigin("http://profile.ak.fbcdn.net"); BrowserPolicy.content.allowImageOrigin("http://graph.facebook.com"); }); 

शीर्षक इस तरह दिखेगा:
 content-security-policy: default-src 'self'; script-src 'self' 'unsafe-inline'; connect-src * 'self'; img-src data: 'self' https://*.googleusercontent.com http://profile.ak.fbcdn.net http://graph.facebook.com; style-src 'self' 'unsafe-inline'; x-frame-options: SAMEORIGIN 

डिफ़ॉल्ट प्रतिबंधों के अलावा, उल्का दस्तावेज़ीकरण अनुशंसा करता है कि आप इनवॉइस जावास्क्रिप्ट को पृष्ठ पर BrowserPolicy.content.disallowInlineScripts () सर्वर साइड (यदि आप इनलाइन जावास्क्रिप्ट का उपयोग नहीं करते हैं) पर कॉल करके निष्पादित करने की अनुमति नहीं देते हैं।

डेटा सत्यापन: चेक () फ़ंक्शन और ऑडिट-तर्क-चेक पैकेज


उल्का सर्वर विधियों और प्रकाशित कार्यों के लिए पारित डेटा को मान्य करने के लिए एक तंत्र प्रदान करता है। ऐसा करने के लिए, चेक () फ़ंक्शन का उद्देश्य है, जिसमें चेक किए गए मान और सत्यापन के लिए टेम्पलेट पास किए गए हैं। टेम्पलेट एक स्पष्ट प्रकार का संकेत हो सकता है, या एक मैच ऑब्जेक्ट जो अधिक जटिल सत्यापन नियमों को परिभाषित करता है (http: //docs.meteor.com/#match देखें)
ऑडिट-तर्क-जांच पैकेज को स्थापित करने से प्रकाशन विधियों और कार्यों का निष्पादन अवरुद्ध हो जाता है जो डेटा पारित नहीं करते थे जो सत्यापन पारित नहीं करते थे।
यदि सत्यापन की आवश्यकता नहीं है, तो आप निम्न पैरामीटर के साथ चेक फ़ंक्शन को कॉल कर सकते हैं
 check(arguments, [Match.Any]) 

पैकेज जोड़ें
 $ mrt add audit-argument-checks 

अब सर्वर विधि को कॉल करने का प्रयास एक त्रुटि लौटाएगा:
 > Meteor.call('testMethod', 'test data', function(err, result) {console.log(err, result);}) undefined errorClass {error: 500, reason: "Internal server error", details: undefined, message: "Internal server error [500]", errorType:"Meteor.Error"…} undefined 

और सर्वर पर:
  Exception while invoking method 'testMethod' Error: Did not check() all arguments during call to 'testMethod' 

सर्वर विधि में सत्यापन जोड़ने के बाद, यह फिर से सही ढंग से काम करना शुरू कर देगा:
  check(data, String); 


एक निष्कर्ष के बजाय


अपने घटनाक्रम को साझा करने की कोशिश करते हुए, मैंने इस बात पर ध्यान नहीं दिया कि सामग्री कितनी बड़ी मात्रा में निकली, इस तथ्य के बावजूद कि संक्षेप में मैं केवल उल्का के एक बहुत, बहुत छोटे हिस्से को प्रभावित कर सकता था।
मुझे आशा है कि यह पाठ आपको उल्का को और करीब से जानने और इसके बारे में कुछ नया जानने में मदद करेगा।

Source: https://habr.com/ru/post/In211020/


All Articles