2009-04-20 8 views
5

मेरे पास एक Django एप्लिकेशन है जो मैं विकसित कर रहा हूं जो सर्वर पर किसी बाहरी प्रोग्राम को सिस्टम कॉल करना होगा। सिस्टम कॉल के लिए कमांड बनाने में, एप्लिकेशन किसी फॉर्म से मान लेता है और कॉल के लिए पैरामीटर के रूप में उनका उपयोग करता है। मुझे लगता है कि इसका मतलब यह है कि कोई अनिवार्य रूप से बोगस पैरामीटर का उपयोग कर सकता है और खोलने के लिए शेल के लिए मनमाना आदेश लिख सकता है (उदा।, केवल अर्धविराम रखें और फिर rm -rf *)।मैं Django ऐप बनाने सिस्टम कॉल से मनमाने ढंग से आदेशों को निष्पादित करने से कैसे रोकूं?

यह बुरा है। जबकि अधिकांश उपयोगकर्ता दुर्भावनापूर्ण नहीं हैं, यह एक संभावित सुरक्षा समस्या है। शोषण के इन संभावित बिंदुओं को कैसे संभाला जाता है?

EDIT (स्पष्टीकरण के लिए): उपयोगकर्ता एक फॉर्म देखेंगे जो प्रत्येक पैरामीटर और विकल्पों के लिए विभिन्न फ़ील्ड के साथ विभाजित होगा। हालांकि कुछ फ़ील्ड खुले टेक्स्ट फ़ील्ड के रूप में उपलब्ध होंगे। इन सभी क्षेत्रों को संयुक्त किया गया है और subprocess.check_call() पर खिलाया गया है। तकनीकी रूप से, हालांकि, यह उपयोगकर्ताओं को कमांड प्रॉम्प्ट को सौंपने से बहुत दूर नहीं है। यह काफी आम होना चाहिए, इसलिए अन्य डेवलपर्स इनपुट को स्वच्छ करने के लिए क्या करते हैं ताकि उन्हें Bobby Tables न मिले।

उत्तर

10

प्रश्न की मेरी समझ के आधार पर, मुझे लगता है कि आप उपयोगकर्ताओं को खोल पर चलाने के लिए आदेश निर्दिष्ट नहीं कर रहे हैं, लेकिन केवल उन आदेशों के लिए तर्क। इस मामले में, आप subprocess मॉड्यूल और नहीं का उपयोग कर खोल का उपयोग करके shell injection हमलों से बचने कर सकते हैं (यानी subprocess.Popen निर्माता में डिफ़ॉल्ट shell=False पैरामीटर का उपयोग निर्दिष्ट करें।

ओह, और कभी नहीं उपयोग os.system() शामिल करने वाली तार के लिए उपयोगकर्ता से आने वाले किसी भी इनपुट।

+0

http://blog.littleimpact.de/index.php/2008/08/11/avoiding-shell-injection-in-ruby-python-and-php/ के माध्यम से पढ़ना ऐसा लगता है कि मैं ठीक हूँ शेल = गलत के रूप में लंबे, जो डिफ़ॉल्ट है। (वह है, एक, और केवल एक आदेश चलाया जाएगा।) क्या यह भी आप क्या कह रहे हैं? – gotgenes

+0

हां, यही वह है जो मैं कह रहा हूं। –

3

उत्तर है, उपयोगकर्ताओं को खोल कमांड में टाइप करने दें! मनमाने ढंग से खोल कमांड को निष्पादित करने की अनुमति देने का कोई बहाना नहीं है।

इसके अलावा, यदि आपको वास्तव में बाहरी आदेशों के लिए तर्क प्रदान करने की अनुमति देनी है, तो खोल का उपयोग न करें। सी में, आप सीधे आदेश के लिए तर्क प्रदान करने के लिए execvp() का उपयोग कर सकते हैं, लेकिन django के साथ, मुझे यकीन नहीं है कि आप यह कैसे करेंगे (लेकिन मुझे यकीन है कि एक तरीका है)। बेशक, आपको अभी भी कुछ तर्क स्वच्छता करना चाहिए, खासकर यदि कमांड में किसी भी नुकसान का कारण बनने की क्षमता है।

0

अपने आदेशों की सीमा के आधार पर, आप फॉर्म को कस्टमाइज़ कर सकते हैं, ताकि पैरामीटर अलग-अलग फॉर्म-फ़ील्ड में दर्ज हो जाएं। वे आप फिट बैठने के मूल्यों को अधिक आसानी से पार्स कर सकते हैं। इसके अलावा, बैकटिक्स और अन्य खोल विशिष्ट सामान से सावधान रहें।

6

उपयोगकर्ताओं पर भरोसा न करें। वेब ब्राउज़र से आने वाले किसी भी डेटा को दंडित किया जाना चाहिए। और पूरी तरह से जेएस के माध्यम से डेटा को सत्यापित करने की कोशिश न करें या FORM फ़ील्ड में क्या दर्ज किया जा सकता है आपको अपने बाहरी एप्पल में जाने से पहले सर्वर पर परीक्षण करने की आवश्यकता है कटियन।

अद्यतन आपके संपादन के बाद: कोई फर्क नहीं पड़ता कि कैसे आप अपने सामने के अंत बैकएंड यह व्यवहार करना चाहिए जैसे कि यह उनके आसपास बड़ा चमकती पाठ के साथ पाठ बॉक्स का एक सेट से आया और कहा, "डालने पर उपयोगकर्ताओं के लिए प्रपत्र प्रस्तुत जो कुछ भी तुम यहाँ चाहते हो! "

+0

अच्छा बिंदु। मुझे नहीं लगता कि ग्राहक जिम्मेदार और मान्य होगा; आदेश चलाने से पहले मैं सर्वर पक्ष पर सत्यापन करूँगा। हालांकि, दूसरों के लाभ के लिए, यह आपके कहने लायक है। – gotgenes

4

ऐसा करने के लिए, आपको निम्न कार्य करना होगा। यदि आपको नहीं पता कि "विकल्प" और "तर्क" क्या हैं, तो optparse background पढ़ें।

प्रत्येक "कमांड" या "अनुरोध" वास्तव में एक मॉडल का एक उदाहरण है। अपने अनुरोध मॉडल को परिभाषित करने वाले सभी पैरामीटर के साथ परिभाषित करें।

  1. सरल विकल्पों के लिए, आपको CHOICES की एक विशिष्ट सूची के साथ एक फ़ील्ड प्रदान करना होगा। कमांड लाइन में "चालू" या "ऑफ" (-x) विकल्पों के लिए आपको दो मानव-समझने योग्य मानों ("एक्स एक्स" और "एक्स न करें" के साथ एक CHOICE सूची प्रदान करनी चाहिए।)

  2. किसी मान वाले विकल्पों के लिए, आपको एक फ़ील्ड प्रदान करना होगा जो विकल्प का मान लेता है। आपको इस क्षेत्र के सत्यापन के साथ एक फॉर्म लिखना होगा। हम थोड़ा सा विकल्प मान सत्यापन पर वापस आ जाएंगे।

  3. तर्क के लिए, आपके पास दूसरा मॉडल है (पहले एफके के साथ)। यह एक फ़ाइलपैथ फ़ील्ड जितना आसान हो सकता है, या अधिक जटिल हो सकता है। फिर, आपको इस मॉडल के उदाहरणों को प्रमाणित करने के लिए एक फॉर्म भी प्रदान करना पड़ सकता है।

विकल्प सत्यापन किस तरह का विकल्प बदलता है। आपको स्वीकार्य मानों को वर्णों के सबसे कम संभव सेट के रूप में सीमित करना होगा और एक पार्सर लिखना चाहिए जो केवल वैध वर्णों को पारित करने के बारे में पूरी तरह से सुनिश्चित है।

आपके विकल्प ऑप्टपरसे-स्ट्रिंग, int, long, choice, float और complex में विकल्प प्रकारों के समान श्रेणियों में आ जाएंगे। ध्यान दें कि int, long, float और complex में पहले से ही Django के मॉडल और प्रपत्रों द्वारा परिभाषित सत्यापन नियम हैं। चॉइस एक विशेष प्रकार की स्ट्रिंग है, जो पहले ही डीजेगो के मॉडल और फॉर्म द्वारा समर्थित है।

"स्ट्रिंग्स" क्या बचा है। अनुमत तारों को परिभाषित करें। उन तारों के लिए एक regex लिखें। रेगेक्स का उपयोग करके मान्य करें। अधिकांश समय, आप कभी भी किसी भी रूप में उद्धरण (", ' या `) स्वीकार नहीं कर सकते हैं।

अंतिम चरण। आपके मॉडल में एक विधि है जो आदेश को subprocess.Popen के लिए तैयार स्ट्रिंग के अनुक्रम के रूप में उत्सर्जित करती है।


संपादित

यह हमारे app की रीढ़ है। यह बहुत आम है, हमारे पास एक ही मॉडल है जिसमें कई फॉर्म हैं, प्रत्येक एक विशेष बैच कमांड के लिए जो रन हो जाता है। मॉडल बहुत सामान्य है। मॉडल ऑब्जेक्ट बनाने के लिए फॉर्म बहुत विशिष्ट तरीके हैं। इस तरह Django को काम करने के लिए डिज़ाइन किया गया है, और यह Django के अच्छी तरह से विचार-विमर्श डिजाइन पैटर्न के साथ फिट करने में मदद करता है।

कोई भी क्षेत्र जो "खुले पाठ फ़ील्ड के रूप में उपलब्ध है" एक गलती है। "खुले" वाले प्रत्येक फ़ील्ड में निर्दिष्ट करने के लिए एक रेगेक्स होना चाहिए जो अनुमति है। यदि आप रेगेक्स को औपचारिक रूप से औपचारिक नहीं कर सकते हैं, तो आपको उस पर पुनर्विचार करना होगा जो आप कर रहे हैं।

एक फ़ील्ड जिसे रेगेक्स के साथ बाध्य नहीं किया जा सकता है बिल्कुल कमांड लाइन पैरामीटर नहीं हो सकता है। अवधि। इसे इस्तेमाल होने से पहले फ़ाइल कॉलम में फ़ाइल में संग्रहीत किया जाना चाहिए।


संपादित

इस तरह।

class MySubprocessCommandClass(models.Model): 
    myOption_1 = models.CharField(choice = OPTION_1_CHOICES, max_length=2) 
    myOption_2 = models.CharField(max_length=20) 
    etc. 
    def theCommand(self): 
     return [ "theCommand", "-p", self.myOption_1, "-r", self.myOption_2, etc. ] 

आपका फॉर्म इस मॉडल के लिए मॉडलफॉर्म है।

आपको मॉडल के उदाहरण save() नहीं है। हम उन्हें बचाते हैं ताकि हम ठीक से चलने वाले लॉग का एक लॉग बना सकें।

+0

आपके उत्तर के लिए धन्यवाद। रिक कोपलैंड का जवाब इंगित करता है कि उसमें उपप्रोसेस मॉड्यूल में सुरक्षा शामिल है, जब तक कि खोल = गलत, एक और केवल एक कमांड निष्पादित किया जाएगा; प्रारंभिक कमांड के बाद अन्य सभी भागों को कमांड के लिए तर्क के रूप में माना जाता है। चूंकि मैं शुरुआत में एक कमांड को नियंत्रित करता हूं, क्या मुझे तर्कों के लिए वास्तव में regexps डिज़ाइन करने की ज़रूरत है? – gotgenes

+0

इसके अलावा, मैं उत्सुक हूं, मॉडल क्यों आवश्यक है? जैसा कि आपने कहा है, मुझे सबकुछ एक साथ रखने में कठिनाई हो रही है। हमारे रूप को पहले से ही रूपों के उप-वर्ग के रूप में दर्शाया गया है। फॉर्म; हम इस समय सत्यापन के लिए इसका उपयोग कर रहे हैं। यह मॉडल में कैसे जुड़ता है। क्या आप आदेश को वास्तविक (बेस) कमांड क्लास का जिक्र कर रहे हैं, django.core.management.base से? – gotgenes

+0

प्रबंधन के साथ कुछ भी नहीं करना है। कमांड पदानुक्रम। नहीं, यह कमान पूरी तरह से अलग है। –

संबंधित मुद्दे