2009-12-19 10 views
21

मैंने कई जगहों पर यह कई बार देखा है, लेकिन यह कभी भी एक संतोषजनक स्पष्टीकरण नहीं मिला है कि यह क्यों होना चाहिए।निष्पादन() और eval() क्यों टालना चाहिए?

तो, उम्मीद है कि, यहां एक प्रस्तुत किया जाएगा। हमें (कम से कम, आम तौर पर) exec() और eval() का उपयोग क्यों नहीं करना चाहिए?

संपादित करें: मुझे लगता है कि लोग मानते हैं कि यह प्रश्न वेब सर्वर से संबंधित है - ऐसा नहीं है। मैं देख सकता हूं कि क्यों एक unsanitized स्ट्रिंग exec को पारित किया जा सकता है बुरा हो सकता है। क्या यह गैर-वेब अनुप्रयोगों में खराब है?

+1

क्या आप "एकाधिक स्थानों" से कुछ उद्धरण प्रदान कर सकते हैं ताकि यह स्पष्ट किया जा सके कि आप किस टिप्पणी पर आधारित हैं। यह जानना महत्वपूर्ण है कि आप क्या पढ़ते हैं जो निष्कर्ष निकाला जाता है कि उन्हें टालना चाहिए। यह एक साधारण मुद्दा नहीं है, और आपको अपने प्रश्न को स्पष्ट करने के लिए जानकारी का स्रोत प्रदान करने की आवश्यकता है। –

+0

आम तौर पर, जो मुझे याद है (जैसा कि मैंने पिछले कुछ वर्षों में इन स्थानों को बुकमार्क नहीं किया है), चेतावनियां "निश्चित रूप से, इस मुद्दे को हल करने के लिए 'eval()' का उपयोग कर सकती हैं, लेकिन यह शरारती होगी । " – Isaac

+0

मुझे लगता है कि सबसे हालिया उदाहरण प्रोग्राम के भीतर नियंत्रण प्रवाह के साधन के रूप में 'exec()' का उपयोग कर रहा था। – Isaac

उत्तर

16

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

उदाहरण: मैंने कोड लिखा है जो स्ट्रिंग कुंजी और मानों में पढ़ता है और किसी ऑब्जेक्ट में संबंधित फ़ील्ड सेट करता है। ऐसा लगता है:

for key, val in values: 
    fieldName = valueToFieldName[key] 
    fieldType = fieldNameToType[fieldName] 
    if fieldType is int: 
     s = 'object.%s = int(%s)' % (fieldName, fieldType) 
    #Many clauses like this... 

exec(s) 

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

कोड स्पष्टता का पहला नियम यह है कि आपके कोड की प्रत्येक पंक्ति केवल इसके आस-पास की रेखाओं को देखकर समझना आसान होनी चाहिए। यही कारण है कि गोटो और वैश्विक चर निराश हैं। निष्पादन और eval इस नियम को बुरी तरह से तोड़ना आसान बनाता है।

+1

स्ट्रा मैन तर्क लगभग, आपको अभी तक ** ** ** निष्पादित करने के लिए एक स्ट्रिंग बनाने के लिए कभी भी प्राप्त नहीं करना चाहिए। एक शाब्दिक पास करना काफी खराब है। यदि आपको इसकी आवश्यकता भी नहीं है तो निष्पादन का उपयोग करने के लिए और भी भयानक नहीं है? 'setattr' बेहतर काम करेगा। हालांकि, आप पाइथन के साथ इतना अनुभवी नहीं हैं; 'फ़ील्ड टाइप टाइप int है? और '(int)% s' ?? – u0b34a0f6ae

+12

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

3

इन फ़ंक्शंस को ऐसे संदर्भ में अनुमति देना जहां वे उपयोगकर्ता इनपुट चला सकते हैं, एक सुरक्षा समस्या है, और वास्तव में काम करने वाले सैनिटाइज़र लिखना मुश्किल है।

+0

तो वेब अनुप्रयोग के संदर्भ में उपयोग करना केवल बुरा है? – Isaac

+2

क्या आप कमांड लाइन पर सभी उपयोगकर्ता भरोसेमंद हैं? हो सकता है कि आपको इसके बारे में भी चिंतित होना चाहिए ... – dmckee

+2

नहीं। उन्हें किसी ऐसे व्यक्ति द्वारा विशेषाधिकार वृद्धि के हमले के हिस्से के रूप में उपयोग किया जा सकता है जिसके पास मशीन पर रूट पहुंच नहीं है लेकिन स्क्रिप्ट चलाने के लिए इसका उपयोग है। – Rushyo

2
s = "import shutil; shutil.rmtree('/nonexisting')" 
eval(s) 

अब मान लें कि कोई वेब अनुप्रयोग से एस को नियंत्रित कर सकता है, उदाहरण के लिए। यह पैर में अपने आप को शूट करने के लिए बहुत आसान है:

आपके कंप्यूटर

+0

आप कुछ भी मान सकते हैं –

+5

बस एक एफवाईआई, जो काम नहीं करता है। आप केवल एक अभिव्यक्ति को एक eval स्टेटमेंट में एम्बेड कर सकते हैं। यह दो बयानों को एम्बेड करता है .... वास्तव में, इसे चेतावनी की आवश्यकता हो सकती है क्योंकि मुझे अभी एहसास हुआ है कि मैंने अपने कंप्यूटर पर उन दो पंक्तियों को आजमाया है। : -/ –

+1

__import __ ("शटल") के बारे में क्या है। Rmtree, यह एक अभिव्यक्ति है –

2

एक ही कारण है कि आप रूट के रूप में प्रवेश नहीं करना चाहिए पर ऐसा करने के लिए कोशिश मत करो।

+3

और शायद सबसे महत्वपूर्ण बात यह है कि किसी और के लिए आपको पैर में शूट करना है। या सिर। या बस पूरी इमारत उड़ाओ। –

1

कारण # 1: एक सुरक्षा दोष (यानी प्रोग्रामिंग त्रुटियां ... और हम दावा नहीं कर सकते कि उनसे बचा जा सकता है) और आपने उपयोगकर्ता को सर्वर के खोल तक पहुंच प्रदान की है।

1

इंटरैक्टिव दुभाषिया में यह कोशिश करो और देखो क्या होता है:

>>> import sys 
>>> eval('{"name" : %s}' % ("sys.exit(1)")) 
बेशक

, यह एक कोने मामला है, लेकिन यह इस तरह बातें रोकने के लिए मुश्किल हो सकता है।

+0

आप किसी भी मॉड्यूल आयात किए बिना बाहर निकलें() का भी उपयोग कर सकते हैं। – badp

+2

मुझे याद नहीं है कि यह कहां से आता है, लेकिन बाहर निकलने वाला फ़ंक्शन अंतर्निहित नहीं है। दस्तावेज़ीकरण में कहीं, यह कहता है कि आपको इंटरैक्टिव दुभाषिया को छोड़कर मौजूदा इस कार्य पर भरोसा नहीं करना चाहिए। बेशक, यदि आप किसी सिस्टम में तोड़ने की कोशिश कर रहे हैं तो इससे कोई फर्क नहीं पड़ता। :-) –

9

सुरक्षा एक तरफ, eval और exec अक्सर जटिलता के कारण अवांछित के रूप में चिह्नित किया जाता है। जब आप eval कॉल देखते हैं तो आप अक्सर यह नहीं जानते कि वास्तव में इसके पीछे क्या चल रहा है, क्योंकि यह आमतौर पर एक चर में डेटा पर कार्य करता है। यह कोड को पढ़ने के लिए कठिन बनाता है।

दुभाषिया की पूरी शक्ति का आह्वान करना एक भारी हथियार है जिसे केवल बहुत मुश्किल मामलों के लिए आरक्षित किया जाना चाहिए। ज्यादातर मामलों में, हालांकि, यह सबसे अच्छा से बचा है और सरल उपकरण नियोजित किया जाना चाहिए।

कहा, सभी सामान्यीकरणों की तरह, इस से सावधान रहें।कुछ मामलों में, निष्पादन और eval मूल्यवान हो सकता है। लेकिन आपके पास उनका उपयोग करने का बहुत अच्छा कारण होना चाहिए। एक स्वीकार्य उपयोग के लिए this post देखें।

+0

ऐसा लगता है कि एक उत्तर चुना गया था कि ** ** 'exec()' का उपयोग नहीं किया गया था ... ऐसे मामले हैं जहां 'exec()' या 'eval()' आवश्यक हैं/बीमार नहीं हैं- सलाह दी? – Isaac

+0

उत्तर सेकेंड किया गया। रखरखाव दुःस्वप्न की तरह एक तरफ सुरक्षा, eval और exec देखो। –

+0

@Isaac, उत्तर चुना गया था क्योंकि मैं निष्पादन के बिना कार्य को पूरा करने के तरीकों की तलाश में था। सामान्य मामले में, यह निष्पादन के लिए एक अच्छा उपयोग था, जिसे मैंने समाप्त कर दिया क्योंकि विधियां अधिक मनमानी बन गईं –

8

eval() और exec() आलसी प्रोग्रामिंग को बढ़ावा दे सकता है। अधिक महत्वपूर्ण बात यह इंगित करती है कि निष्पादित कोड को डिजाइन समय पर लिखा नहीं गया हो सकता है इसलिए परीक्षण नहीं किया गया है। दूसरे शब्दों में, आप गतिशील रूप से जेनरेट कोड का परीक्षण कैसे करते हैं? खासकर ब्राउज़रों में।

+3

+1: "मौलिक अपेक्षा" यह है कि आपके पास सभी स्रोत हैं। Exec() और eval() के साथ आप नहीं - trivially - * सब * स्रोत है। –

5

मैंने अतीत में eval() (और अभी भी समय-समय पर) का उपयोग त्वरित और गंदे संचालन के दौरान डेटा मालिश करने के लिए किया है। यह टूलकिट का हिस्सा है जिसका उपयोग नौकरी पाने के लिए किया जा सकता है, लेकिन किसी भी चीज के लिए कभी भी इस्तेमाल नहीं किया जाना चाहिए जिसका उपयोग आप उत्पादन में उपयोग करने की योजना बना रहे हैं जैसे कि कमांड लाइन टूल्स या स्क्रिप्ट्स, दूसरे में उल्लिखित सभी कारणों से जवाब।

आप अपने उपयोगकर्ताओं पर भरोसा नहीं कर सकते - कभी-कभी सही काम करने के लिए। ज्यादातर मामलों में वे करेंगे, लेकिन आपको उन सभी चीजों को करने की उम्मीद करनी होगी जिन्हें आपने कभी नहीं सोचा था और उन सभी बगों को नहीं ढूंढ पाए जिन्हें आपने कभी उम्मीद नहीं की थी। यह ठीक है जहां eval() एक देयता के लिए एक उपकरण होने से चला जाता है।

QuerySet का निर्माण करते समय इसका एक आदर्श उदाहरण Django का उपयोग करेगा।

results = Foo.objects.filter(whatever__contains='pizza') 

आप प्रोग्राम तर्क बताए रहे हैं, तो आप इस तरह कुछ करने के लिए सोच सकते हैं:

results = eval("Foo.objects.filter(%s__%s=%s)" % (field, matcher, value)) 

लेकिन वहाँ है मापदंडों एक सवाल के पारित कर दिया कीवर्ड तर्क, कि कुछ इस तरह दिखाई स्वीकार करता है हमेशा एक बेहतर तरीका है कि eval(), जो संदर्भ द्वारा एक शब्दकोश गुजर रहा है का उपयोग नहीं करता:

results = Foo.objects.filter(**{'%s__%s' % (field, matcher): value}) 

इसे इस तरह करने से, यह न केवल तेजी से perfo है rmance-wise, लेकिन सुरक्षित और अधिक पाइथोनिक भी।

कहानी का नैतिक? लगभग निश्चित रूप से यह करने के लिए एक बेहतर तरीका है, क्योंकि वहाँ हमेशा

eval() का प्रयोग छोटे कार्यों, परीक्षण, और सही मायने में अस्थायी बातों के लिए ठीक, लेकिन स्थायी उपयोग के लिए बुरा है!

+0

+1 यह बताते हुए कि 'eval() 'का उपयोग घर से बढ़ी हुई स्क्रिप्ट में पूरी तरह से ठीक है। – akuhn

+1

ठीक है, जब तक कि घर से उगने वाली लिपियों ने घोंसला छोड़ दिया और व्यापक रूप से उपयोग नहीं किया, क्योंकि वे ऐसा करने के लिए नहीं हैं। –

+0

यदि आपने कभी भी उत्पादन में सजावटी मॉड्यूल का उपयोग किया है (साथ ही साथ कई अन्य libs), तो आपने उत्पादन में निष्पादन का उपयोग किया है। निष्पादन और eval एक अंतिम उपयोगकर्ता द्वारा डेटा इनपुट के अलावा कई चीजों के लिए उपयोगी हैं। – zzzeek

10

जब आपको निष्पादन और eval की आवश्यकता है, हाँ, आपको वास्तव में उनकी आवश्यकता है।

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

, उचित भागने और फ़िल्टरिंग के साथ, निष्पादन का उपयोग और सुरक्षित रूप से eval के साथ कर सकते हैं। लेकिन एक प्रकार का कोडर जो किसी समस्या को हल करने के लिए सीधे निष्पादन/निकालने के लिए जाता है (क्योंकि वे भाषा को उपलब्ध अन्य सुविधाओं को समझ नहीं पाते हैं) यह कोडर की तरह नहीं है जो उस प्रसंस्करण को सही करने में सक्षम होगा; यह ऐसा व्यक्ति होने वाला है जो स्ट्रिंग प्रसंस्करण को समझ में नहीं आता है और केवल अंधेरे से सबस्ट्रिंग को जोड़ता है, जिसके परिणामस्वरूप नाजुक असुरक्षित कोड होता है।

यह स्ट्रिंग्स का लुभावना है। के आसपास स्ट्रिंग सेगमेंट फेंकने से आसान लगता है और मूर्खतापूर्ण कोडर सोचते हैं कि वे समझते हैं कि वे क्या कर रहे हैं। लेकिन अनुभव से पता चलता है कि परिणाम कुछ कोने (या गैर-कोने) मामले में लगभग हमेशा गलत होते हैं, अक्सर संभावित सुरक्षा प्रभावों के साथ।यही कारण है कि हम कहते हैं कि eval बुरा है। यही कारण है कि हम कहते हैं कि regex-for-HTML बुरा है। यही कारण है कि हम एसक्यूएल पैरामीटरकरण धक्का। हां, आप मैन्युअल स्ट्रिंग प्रोसेसिंग के साथ इन सभी चीजों को सही कर सकते हैं ... लेकिन जब तक कि आप पहले से ही समझ नहीं पाते हैं कि हम उन चीजों को क्यों कहते हैं, तो संभावना है कि आप नहीं होंगे।

7

अधिकांश जवाब यहां क्या कह रहे हैं इसके विपरीत, निष्पादन वास्तव में पाइथन में सुपर-पूर्ण सजावट बनाने के लिए नुस्खा का हिस्सा है, क्योंकि आप सजाए गए फ़ंक्शन के बारे में सबकुछ डुप्लिकेट कर सकते हैं, दस्तावेज़ीकरण के उद्देश्यों के लिए समान हस्ताक्षर का उत्पादन कर सकते हैं और ऐसा। यह व्यापक रूप से प्रयुक्त सजावटी मॉड्यूल की कार्यक्षमता की कुंजी है (http://pypi.python.org/pypi/decorator/)। अन्य मामलों में जहां निष्पादन/eval आवश्यक है, किसी भी प्रकार का "व्याख्याित पायथन" प्रकार का अनुप्रयोग, जैसे कि पाइथन-पार्सेड टेम्पलेट भाषा (जैसे मको या जिनजा) का निर्माण करना।

तो ऐसा नहीं है कि इन कार्यों की उपस्थिति एक "असुरक्षित" एप्लिकेशन या लाइब्रेरी का तत्काल संकेत है। आने वाले JSON या किसी चीज़ का मूल्यांकन करने के लिए बेवकूफ जावास्क्रिप्ट तरीके से उनका उपयोग करना, हां यह बहुत असुरक्षित है। लेकिन हमेशा के रूप में, आप इसे जिस तरह से उपयोग करते हैं और ये बहुत ही आवश्यक कार्य हैं।

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