日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

eval()函數是Python/ target=_blank class=infotextkey>Python的內置函數,功能非常強大,但是存在不小的安全隱患。有些企業或項目出于安全考慮,禁止使用eval()函數,會在一些安全相關的掃描校驗中進行識別和攔截,杜絕使用。

究竟eval()函數強大在哪?又有什么安全隱患?本文將逐一進行總結分析。


 

eval()函數介紹

eval()函數語法:

 

eval(expression[, globals[, locals]]) expression: 字符串表達式。globals: 可選參數,全局變量,如果設置,則必須是一個字典對象。locals: 可選參數,局部變量,如果設置,則可以是任何映射(mApping)對象。如果只設置了globals,locals默認與globals一樣。

 

eval()函數的作用是將字符串當成有效的表達式來求值并返回計算的結果。相當于去掉字符串首尾的引號,并執行去掉引號后的語句,返回執行的結果。

主要效果體現為:

 

  • 執行一個字符串表達式,并返回表達式的值。
  • 將字符串轉成對應格式的數據對象(如int、list、tuple或dict)。

 

eval()函數的強大功能

1.執行字符串表達式并返回結果。

# 計算表達式 s = eval("5 + 7") print('s: ', s) s1 = eval('[i for i in range(10)]') print('s1: ', s1) 1234512345

Output:

s: 12 s1: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 1212

eval()可以對字符串中的數字加法進行計算,返回計算結果。也可以直接執行字符串中的列表推導式這類表達式,返回執行的結果。

2.執行表達式時支持將變量傳到字符串中。

# 傳入變量 x = 111 s2 = eval("123 + x") print('s2: ', s2) # 設置globals y = 2222 s3 = eval("1234 + y", {"y": 1111}) print('s3: ', s3) # 設置globals, locals z = 22222 s4 = eval("12345 + z", {"z": 11111}, {"z": 33333}) print('s4: ', s4) 123456789101112123456789101112

Output:

s2: 234 s3: 2345 s4: 45678 123123

在eval()中執行表達式還支持傳參,可以在當前 .py 代碼環境中定義變量,也可以通過eval()函數的globals參數和locals參數傳值。優先級locals高于globals,globals高于當前 .py代碼環境的變量。

3.返回對應類型的數據。

# 將引號中的內容還原成對應類型的數據 sta = '12345' print(type(eval(sta)), eval(sta)) stb = '[1, 2, 3, 4, 5, 6, 7]' print(type(eval(stb)), eval(stb)) stc = '(2, 4, 6, 8, 10)' print(type(eval(stc)), eval(stc)) std = '{"beijing": 1, "shanghai": 2, "guangzhou": 3, "shenzhen": 4}' print(type(eval(std)), eval(std)) 123456789123456789

Output:

12345 [1, 2, 3, 4, 5, 6, 7] (2, 4, 6, 8, 10) {'beijing': 1, 'shanghai': 2, 'guangzhou': 3, 'shenzhen': 4} 12341234

eval()函數直接返回字符串內容對應的數據類型,作用相當于將字符串首尾的引號去掉,如果不用eval(),自己轉換數據類型,需要好幾個步驟。


 

eval()函數經常和input()函數配合使用,直接將用戶輸入的字符串轉換成對應類型的數據。

eval()函數也經常用于從配置文件中讀取內容,讀取內容的同時直接轉換成對應類型。

eval()函數的安全隱患

eval()函數功能非常強大,但同時也存在不小的安全隱患,原因正是eval()可以將字符串轉成表達式執行。

# 調用庫執行系統命令 import os eval("os.system('whoami')") eval("os.system('echo 123')") 1234512345

Output:

desktop-xxxxxx 123 1212

如果在執行eval()函數的運行環境中導入了os模塊,惡意用戶可以通過eval()函數調用os模塊中的系統命令函數system(),執行一系列的系統命令來達到他的目的。

如os.system(‘whoami’)可以查看當前系統的登錄用戶、os.system(‘dir’)可以查看當前目錄下的所有文件。假如執行的是查看源碼或刪除數據等的命令,將會產生嚴重的后果。

針對這種隱患,有沒有辦法限制用戶執行系統命令呢?

Import os print('os' in globals()) eval("os.system('whoami')") print("*"*30) # 將globals參數設置成空 eval("os.system('whoami')", {}, {}) eval("os.system('whoami')", {}) 1234567812345678

Output:

True desktop-xxxxxx ****************************** Traceback (most recent call last): File "C:/Users/xxx/Desktop/eval_demo.py", line 49, in eval("os.system('whoami')", {}, {}) File "", line 1, in NameError: name 'os' is not defined 1234567812345678

上面的代碼運行環境中導入了os庫,eval()中可以正常調用。假如將eval()中的globals和locals參數設置成空,eval()中就找不到os庫了,執行代碼報錯。

eval()函數中變量加載的優先級順序為:局部變量locals > 全局變量globals > 當前 .py環境中的變量。

這里需要注意,如果未設置locals或locals為空,則locals與globals一樣。假如locals中不存在值,會再到globals中尋找值。因此,要設置locals和globals中都沒有os庫,才能避免用戶調用。(實際應用時并不一定都是將locals和globals設置為空,設置為空只是一種示例)。

通過對locals和globals的限制,避免了用戶調用當前運行環境中導入的os庫。但是,限制用戶使用已導入的庫,用戶可以自己導入庫并使用。

# 導入os庫并執行系統命令 eval("__import__('os').system('whoami')") eval("__import__('os').system('echo 123')") # 增加globals和locals的限制 eval("__import__('os').system('whoami')", {}) eval("__import__('os').system('echo 123')", {}, {}) 123456123456

Output:

desktop-xxxxxx 123 desktop-xxxxxx 123 12341234

如果惡意用戶發現當前的運行環境中沒有導入os,或者導入的os庫被限制使用,調用os.system()報錯。惡意用戶會嘗試自己導包,用__import__(‘os’)可以在eval()函數中導入os庫,同時執行一系列的系統命令來達到他的目的。

這種方法是在每次執行時都導包,并立即鏈式執行系統命令,在globals和locals中去掉os并不能起到限制。而且,os庫是python中的標準庫,只要有python就一定有os庫,用戶必然能導入成功。

那針對這種隱患,有沒有辦法不讓用戶導包呢?

# 在globals中將__builtins__設置為None eval("__import__('os').system('whoami')", {"__builtins__": None}) 1212

Output:

Traceback (most recent call last): File "C:/Users/xxx/Desktop/eval_demo.py", line 62, in eval("__import__('os').system('whoami')", {"__builtins__": None}) File "", line 1, in TypeError: 'N.NEType' object is not subscriptable 1234512345

用戶自己在eval()函數中導包,是使用__import__()函數實現的。__import__()函數是python的內建函數,是用于動態導庫的函數。

print(dir(__builtins__)) 11

Output:

['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'bytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'windowsError', 'ZeroDivisionError', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'breakpoint', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip'] 11

在python中,內建函數都在__builtins__模塊中,在啟動python時,python解釋器就直接導入了__builtins__模塊中的函數。__import__()函數就是__builtins__模塊中的一員,也就是說,python解釋器默認導入了__import__()函數,用戶可以直接調用。

上面的代碼在globals參數中將__builtins__設置成None,eval()函數就獲取不到__import__()函數了,無法自己導包,執行代碼報錯。

但是,限制用戶導包,惡意用戶還可以通過其他途徑獲取到os庫。

s = '[x for x in ().__class__.__bases__[0].__subclasses__() if x.__name__ == "zipimporter"][0]("C:/Users/xxx/Lib/site-packages/setuptools-28.8.0-py3.6.egg").load_module("setuptools").os.system("whoami")' eval(s, {"__builtins__": None}) 1212

Output:

desktop-xxxxxx 11

上面這種方式也可以成功執行系統命令。代碼中利用__class__和__subclasses__動態加載了基類object的所有子類(可以執行下面這行代碼查看當前環境中基類都有哪些子類),然后找到了zipimporter,用zipimporter動態加載setuptools庫的 .egg包,再鏈式調用load_module()成功導入setuptools庫,從而成功調用os庫執行系統命令。


 

print([x.__name__ for x in ().__class__.__bases__[0].__subclasses__()]) 11

在python中,有一些庫中內置了os庫,導入這些庫后就能調用os庫,其中就包含setuptools,此外還有configobj、urllib、urllib2等。

當然,執行上面的代碼需要有對應的.egg包,如果你也想演示看效果,你可以先在自己的電腦磁盤中全局搜一下,找不到再到網絡下載。

以上是eval()函數的一些安全隱患,可謂是防不勝防,在寫代碼時無形中就需要和惡意用戶進行很多回合的思維對抗,假如有哪個細節稍微考慮不周,就會留下很大的隱患。而且,關于eval(),惡意用戶還有很多可以利用的方法,如刪數據、暴力占滿服務器的CPU資源等。

既然用了就防不勝防,那只有不用才不會留下隱患,所以,在一些企業和項目中就禁用了eval()函數。

(當然,python中也有替代方案,那就是ast.literal_eval()函數,ast.literal_eval()函數會判斷字符串內容去掉首尾的引號后是不是合法的python類型,如果不是就報錯,因此ast.literal_eval()函數也只能進行類型轉換。)

分享到:
標簽:python
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定