अजगर का उपयोग () बनाम ast.literal_eval () का उपयोग?


176

मेरे पास कुछ कोड के साथ एक स्थिति है जहां eval()संभव समाधान के रूप में आया। अब मुझे पहले कभी भी इसका उपयोग नहीं करना पड़ा है eval(), लेकिन इसके संभावित खतरे के बारे में मुझे बहुत सारी जानकारी है। उस ने कहा, मैं इसे इस्तेमाल करने के बारे में बहुत सावधान हूँ।

मेरी स्थिति यह है कि मेरे पास उपयोगकर्ता द्वारा दिया जा रहा इनपुट है:

datamap = raw_input('Provide some data here: ')

जहां datamapएक शब्दकोश होना चाहिए। मैंने आसपास खोज की और पाया कि eval()यह काम कर सकता है। मैंने सोचा था कि डेटा का उपयोग करने से पहले मैं इनपुट के प्रकार की जांच करने में सक्षम हो सकता हूं और यह एक व्यवहार्य सुरक्षा सावधानी होगी।

datamap = eval(raw_input('Provide some data here: ')
if not isinstance(datamap, dict):
    return

मैं डॉक्स के माध्यम से पढ़ता हूं और मैं अभी भी स्पष्ट नहीं हूं कि यह सुरक्षित होगा या नहीं। क्या डेटा का मूल्यांकन उसके प्रवेश करते ही या datamapचर कहे जाने के बाद होता है?

क्या astमॉड्यूल .literal_eval()एकमात्र सुरक्षित विकल्प है?

जवाबों:


190

datamap = eval(raw_input('Provide some data here: '))इसका मतलब यह है कि आप वास्तव में कोड का मूल्यांकन करते हैं इससे पहले कि आप इसे असुरक्षित या नहीं समझें। यह फ़ंक्शन को कॉल करते ही कोड का मूल्यांकन करता है। के खतरों कोeval भी देखें ।

ast.literal_eval यदि इनपुट वैध पायथन डेटाटाइप नहीं है तो एक अपवाद उठाता है, इसलिए यदि यह नहीं है तो कोड निष्पादित नहीं किया जाएगा।

ast.literal_evalजब भी आपको आवश्यकता हो उपयोग करें eval। आपको आमतौर पर शाब्दिक अजगर के बयानों का मूल्यांकन नहीं करना चाहिए।


20
यह 100% सही सलाह नहीं है क्योंकि कोई भी बिटवाइज़ ऑपरेटर (या ओवरलोड ऑपरेटर) विफल हो जाएगा। उदाहरण के लिए। ast.literal_eval("1 & 1")एक त्रुटि फेंक देंगे, लेकिन eval("1 & 1")नहीं करेंगे।
डैनियल वैन फ्लाईमेन

1
बस उत्सुक। अगर हम "1 & 1" जैसी किसी चीज़ की उम्मीद कर रहे हैं तो क्या हमें अभिव्यक्ति पर्सर्स या कुछ का उपयोग नहीं करना चाहिए?
द क्लिंकर

@tilinuxer आपको अभी भी चाहिए, हाँ; आप बस उस ast.literal_evalचीज़ के लिए उपयोग नहीं कर पाएंगे (जैसे आप मैन्युअल रूप से पार्सर लागू कर सकते हैं)।
अस्थिरता

104

ast.literal_eval() केवल पायथन के सिंटैक्स के एक छोटे उपसमूह को वैध मानता है:

प्रदान की गई स्ट्रिंग या नोड में केवल निम्नलिखित पायथन शाब्दिक संरचनाएं शामिल हो सकती हैं: स्ट्रिंग्स, संख्याएं, ट्यूपल्स, सूचियां, डीकट्स, बुलियन और कोई नहीं।

में पास __import__('os').system('rm -rf /a-path-you-really-care-about')करना ast.literal_eval()एक त्रुटि पैदा करेगा, लेकिन eval()खुशी से आपकी ड्राइव को मिटा देगा।

चूंकि ऐसा लगता है कि आप केवल उपयोगकर्ता इनपुट को एक सादा शब्दकोश दे रहे हैं, उपयोग करें ast.literal_eval()। यह सुरक्षित रूप से वही करता है जो आप चाहते हैं और इससे अधिक कुछ नहीं।


बाइट-स्ट्रिंग्स (क्लास बाइट्स) का भी समर्थन करता है। उदाहरण के लिए। b'Hello World '
XChikuX

52

eval: यह बहुत शक्तिशाली है, लेकिन यह भी बहुत खतरनाक है यदि आप अविश्वासित इनपुट से मूल्यांकन करने के लिए तार स्वीकार करते हैं। मान लीजिये स्ट्रिंग का मूल्यांकन किया जा रहा है "os.system ('rm -rf /')"? यह वास्तव में आपके कंप्यूटर की सभी फाइलों को हटाना शुरू कर देगा।

ast.literal_eval: सुरक्षित रूप से एक अभिव्यक्ति नोड या एक पायथन शाब्दिक या कंटेनर डिस्प्ले युक्त स्ट्रिंग का मूल्यांकन करें। प्रदान की गई स्ट्रिंग या नोड में केवल निम्नलिखित पायथन शाब्दिक संरचनाएं शामिल हो सकती हैं: स्ट्रिंग्स, बाइट्स, संख्याएं, ट्यूपल्स, सूचियां, डीकट्स, सेट, बुलियन, कोई नहीं, बाइट्स और सेट।

वाक्य - विन्यास:

eval(expression, globals=None, locals=None)
import ast
ast.literal_eval(node_or_string)

उदाहरण:

# python 2.x - doesn't accept operators in string format
import ast
ast.literal_eval('[1, 2, 3]')  # output: [1, 2, 3]
ast.literal_eval('1+1') # output: ValueError: malformed string


# python 3.0 -3.6
import ast
ast.literal_eval("1+1") # output : 2
ast.literal_eval("{'a': 2, 'b': 3, 3:'xyz'}") # output : {'a': 2, 'b': 3, 3:'xyz'}
# type dictionary
ast.literal_eval("",{}) # output : Syntax Error required only one parameter
ast.literal_eval("__import__('os').system('rm -rf /')") # output : error

eval("__import__('os').system('rm -rf /')") 
# output : start deleting all the files on your computer.
# restricting using global and local variables
eval("__import__('os').system('rm -rf /')",{'__builtins__':{}},{})
# output : Error due to blocked imports by passing  '__builtins__':{} in global

# But still eval is not safe. we can access and break the code as given below
s = """
(lambda fc=(
lambda n: [
    c for c in 
        ().__class__.__bases__[0].__subclasses__() 
        if c.__name__ == n
    ][0]
):
fc("function")(
    fc("code")(
        0,0,0,0,"KABOOM",(),(),(),"","",0,""
    ),{}
)()
)()
"""
eval(s, {'__builtins__':{}})

उपरोक्त कोड में ().__class__.__bases__[0]केवल वस्तु के अलावा कुछ नहीं। अब हमने सभी उपवर्गों को तात्कालिक कर दिया है , यहाँ हमारा मुख्य enter code hereउद्देश्य है कि हम इसमें से n नाम के एक वर्ग की खोज करें ।

हमें तात्कालिक उपवर्गों से codeवस्तु और functionवस्तु की आवश्यकता है । यह CPythonऑब्जेक्ट के उप-वर्ग तक पहुंचने और सिस्टम को संलग्न करने का एक वैकल्पिक तरीका है।

अजगर से 3.7 ast.literal_eval () अब सख्त है। मनमाना संख्याओं के जोड़ और घटाव की अब अनुमति नहीं है। संपर्क


1
मैं अजगर 2.7 का उपयोग कर रहा हूँ और मैंने अभी अजगर 3.x पर इसके ठीक काम की जाँच की। मेरा बुरा मैं इसे अजगर 2.7
मोर्या

3
ast.literal_eval("1+1")अजगर 3.7 में काम नहीं करता है और जैसा कि पहले कहा गया था, शाब्दिक_कावल उन कुछ डेटा संरचनाओं के शाब्दिक तक सीमित होना चाहिए। यह बाइनरी ऑपरेशन को पार्स करने में सक्षम नहीं होना चाहिए।
सेशु

क्या आप अपना KABOOMकोड बता सकते हैं , कृपया यह यहाँ पाया:KABOOM
winklerrr

2
@winklerrr KABOOMयहाँ अच्छी तरह से समझाया गया है: nedbatchelder.com/blog/201206/eval_really_is_dangerous.html
एलिजास

41

पाइथन के मूल्यांकन में उत्सुक है, इसलिए eval(raw_input(...))जैसे ही evalआप डेटा के साथ क्या करेंगे, उसके हिट होने के बाद ही उपयोगकर्ता के इनपुट का मूल्यांकन करेगा । इसलिए, यह सुरक्षित नहीं है , खासकर जब आप evalउपयोगकर्ता इनपुट करते हैं।

का उपयोग करें ast.literal_eval


एक उदाहरण के रूप में, प्रॉम्प्ट पर इसे दर्ज करना आपके लिए बहुत बुरा होगा:

__import__('os').system('rm -rf /a-path-you-really-care-about')

3

यदि आप सभी की जरूरत है एक उपयोगकर्ता प्रदान शब्दकोश, संभव बेहतर समाधान है json.loads। मुख्य सीमा यह है कि json dicts को स्ट्रिंग कीज़ की आवश्यकता होती है। इसके अलावा, आप केवल शाब्दिक डेटा प्रदान कर सकते हैं, लेकिन यह भी मामला है literal_eval


1

मैं साथ अटका हुआ था ast.literal_eval()। मैं इसे IntelliJ IDEA डिबगर में आज़मा रहा था, और यह Noneडीबगर आउटपुट पर वापस आता रहा ।

लेकिन बाद में जब मैंने इसका उत्पादन एक चर को सौंपा और इसे कोड में मुद्रित किया। यह ठीक काम किया। साझाकरण कोड उदाहरण:

import ast
sample_string = '[{"id":"XYZ_GTTC_TYR", "name":"Suction"}]'
output_value = ast.literal_eval(sample_string)
print(output_value)

इसका पायथन संस्करण 3.6 है।

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