Python 在網路安全領域應用廣泛,但開發者也需留意潛在的安全風險。本文示範如何使用 Python 檢測 Heartbleed 等 SSL/TLS 弱點,並探討 SSLyze 和 Nmap 等工具的應用,以分析伺服器組態並識別潛在風險。此外,文章也涵蓋了 Python 模組中常見的安全問題,例如不安全的輸入驗證和 eval() 函式的使用,並提供相應的解決方案和最佳實務,例如使用 yaml.safe_load() 和輸入驗證來強化程式碼的安全性,避免程式碼注入和資料洩露等風險。這些方法能有效提升 Python 應用程式的安全性,降低遭受攻擊的可能性。
測試 Heartbleed 與 SSL/TLS 弱點
在前面的程式碼中,第一部分包含了嘗試與伺服器在 443 埠進行握手的功能。接下來的部分負責向伺服器傳送一個封包,以檢查伺服器是否可供連線,最後則是負責傳送心跳封包。
print('Sending Client Hello...')
sys.stdout.flush()
s.send(hello)
print('Waiting for Server Hello...')
sys.stdout.flush()
while True:
typ, ver, pay = recvmsg(s)
if typ == None:
print('Server closed connection without sending Server Hello.')
return
# 尋找伺服器 hello done 訊息。
if typ == 22 and pay[0] == 0x0E:
break
print('Sending heartbeat request...')
sys.stdout.flush()
s.send(hb)
hit_hb(s)
內容解密:
此段程式碼展示瞭如何與伺服器建立 SSL/TLS 連線,並檢查伺服器是否存在 Heartbleed 弱點。s.send(hello) 傳送使用者端的 hello 訊息以啟動 SSL/TLS 握手程式。接著,程式碼進入一個迴圈,持續接收伺服器的訊息,直到收到伺服器的 hello done 訊息(typ == 22 and pay[0] == 0x0E)。當收到伺服器的 hello done 訊息後,程式碼傳送一個心跳請求(s.send(hb))並呼叫 hit_hb(s) 函式以處理心跳回應。
在易受攻擊的伺服器上執行上述指令碼後,輸出結果將類別似於以下內容:
Connecting...
Sending Client Hello...
Waiting for Server Hello...
... received message: type = 22, ver = 0302, length = 58
... received message: type = 22, ver = 0302, length = 1549
... received message: type = 22, ver = 0302, length = 781
... received message: type = 22, ver = 0302, length = 4
Sending heartbeat request...
... received message: type = 24, ver = 0302, length = 16384
Received heartbeat response:
0000: 02 40 00 D8 03 02 53 43 5B 90 9D 9B 72 0B BC 0C [email protected][...r...
0010: BC 2B 92 A8 48 97 CF BD 39 04 CC 16 0A 85 03 90 .+..H...9.......
0020: 9F 77 04 33 D4 DE 00 00 66 C0 14 C0 0A C0 22 C0 .w.3....f.....'.
...
使用 Nmap 埠掃描器掃描 Heartbleed 弱點
Nmap 提供了一個 Heartbleed 指令碼,能夠很好地檢測易受攻擊的伺服器。該指令碼可在 OpenSSL-Heartbleed Nmap 指令碼頁面找到:http://nmap.org/nsedoc/scripts/ssl-heartbleed.html
您可以在埠 443 上執行以下命令:
$ nmap -p 443 --script ssl-heartbleed <ip_address>
只需新增目標網站的 IP 地址。如果目標存在弱點,將看到以下輸出:
PORT STATE SERVICE
443/tcp open https
| ssl-heartbleed:
| VULNERABLE:
| The Heartbleed Bug is a serious vulnerability in the popular OpenSSL cryptographic software library. It allows for stealing information intended to be protected by SSL/TLS encryption.
| State: VULNERABLE
| Risk factor: High
| OpenSSL versions 1.0.1 and 1.0.2-beta releases (including 1.0.1f and 1.0.2-beta1) of OpenSSL are affected by the Heartbleed bug. The bug allows for reading memory of systems protected by the vulnerable OpenSSL versions and could allow for disclosure of otherwise encrypted confidential information as well as the encryption keys themselves.
|
| References:
| http://cvedetails.com/cve/2014-0160/
| http://www.openssl.org/news/secadv_20140407.txt
|_ https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-0160
使用 SSLyze 分析 TLS/SSL 組態
SSLyze 是個 Python 工具,與 Python 3.6+ 一起使用,能夠分析伺服器的 SSL 組態以檢測問題,包括不良憑證和危險的加密套件。
此工具可在 Pypi 儲存函式庫中找到(https://pypi.org/project/SSLyze),您可以從原始碼安裝或使用 pip install sslyze 命令安裝。
我們可以在 GitHub 上存取 SSLyze 專案(https://github.com/nabla-c0d3/sslyze),在那裡我們可以找到該工具的原始碼以及官方檔案(https://nabla-c0d3.github.io/sslyze/documentation)。
SSLyze 工具有以下選項:
### SSLyze 的使用選項
* HeartbleedPlugin:測試伺服器是否具有 OpenSSL Heartbleed 弱點(CVE-2014-0160)。
使用 HeartbleedPlugin
HeartbleedPlugin 可用於檢測伺服器是否存在 OpenSSL Heartbleed 弱點。
--heartbleed Test the server(s) for the OpenSSL Heartbleed vulnerability.
使用 SSLyze 掃描 TLS/SSL 組態
當我們針對特定的 IP 地址執行 SSLyze 工具時,它會傳回一份報告,提供有關伺服器所使用的 OpenSSL 密碼套件的資訊。
SSLyze 掃描結果分析
在命令輸出中,我們可以看到它執行了一個常規的 HTTPS 掃描,包括 SSL 版本 2、SSL 版本 3、TLS 1.0、TLS 1.1 和 TLS 1.2,並獲得了有關憑證和可能存在的漏洞的基本資訊。
SSLV3 密碼套件
- 向前保密性 OK - 支援
- RC4 不安全 - 支援
- 首選:
- 無 - 伺服器遵循客戶端密碼套件偏好。
- 已接受:
- TLS_RSA_WITH_SEED_CBC_SHA(128 位元,HTTP 200 OK)
- TLS_RSA_WITH_RC4_128_SHA(128 位元,HTTP 200 OK)
- TLS_RSA_WITH_CAMELLIA_256_CBC_SHA(256 位元,HTTP 200 OK)
- TLS_RSA_WITH_CAMELLIA_128_CBC_SHA(128 位元,HTTP 200 OK)
- TLS_RSA_WITH_AES_256_CBC_SHA(256 位元,HTTP 200 OK)
- TLS_RSA_WITH_AES_128_CBC_SHA(128 位元,HTTP 200 OK)
- TLS_RSA_WITH_3DES_EDE_CBC_SHA(112 位元,HTTP 200 OK)
- TLS_DHE_RSA_WITH_SEED_CBC_SHA(128 位元,HTTP 200 OK)
- TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA(256 位元,HTTP 200 OK)
- TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA(128 位元,HTTP 200 OK)
- TLS_DHE_RSA_WITH_AES_256_CBC_SHA(256 位元,HTTP 200 OK)
- TLS_DHE_RSA_WITH_AES_128_CBC_SHA(128 位元,HTTP 200 OK)
- TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA(112 位元,HTTP 200 OK)
分析結果
這份報告提供了伺服器所支援的 SSL/TLS 版本和密碼套件的詳細資訊,同時也指出了一些潛在的安全問題,例如對 RC4 的支援。
使用 ThreadPoolExecutor 進行平行掃描
SSLyze 工具的一大優勢是能夠同時掃描多個主機。為此,我們可以使用 concurrent.futures 模組中的 ThreadPoolExecutor 類別來平行啟動多個掃描任務。
重點回顧
- 使用 SSLyze 掃描 TLS/SSL 組態
- 分析掃描結果以找出潛在的安全問題
- 使用
ThreadPoolExecutor進行平行掃描
Python 模組中的安全與漏洞
Python 的強大功能使其成為從小型專案到複雜資料處理應用程式的理想選擇。然而,隨著應用程式複雜度的增加,潛在的安全問題和漏洞也隨之增加。本章節將探討 Python 模組中的安全問題和漏洞。
探索 Python 模組中的安全問題
本文將回顧 Python 中可能導致安全問題的函式和模組,例如 eval、pickle、subprocess、os 和 yaml。
Python 中具有安全問題的函式
eval():執行字串形式的 Python 表示式,可能導致程式碼注入攻擊。pickle:用於物件序列化和反序列化,但可能導致任意程式碼執行。subprocess:用於執行外部命令,但如果不當使用,可能導致命令注入攻擊。mktemp:用於建立暫存檔案,但可能導致暫存檔案攻擊。
輸入/輸出驗證
輸入/輸出驗證是防止安全漏洞的關鍵。超過 75% 的安全漏洞是由於輸入驗證不當引起的。攻擊者可能會向程式中注入惡意資料或命令,從而危及機器的安全。
最佳實踐
- 對所有輸入進行嚴格驗證和清理。
- 使用安全的函式和模組,避免使用具有已知安全問題的函式,如
eval()。 - 對輸出進行適當的編碼和轉義,以防止 XSS 等攻擊。
Python模組中的安全性與漏洞探討
在開發Python應用程式時,輸入與輸出的驗證和清理是防止安全漏洞的關鍵步驟。未經驗證的輸入可能導致嚴重的安全問題,攻擊者可能利用此類別漏洞注入惡意程式碼或命令,從而損害系統或應用程式的安全。
不安全的輸入驗證範例
以下範例展示了一個不安全的程式碼片段,該程式碼直接使用使用者輸入的引數執行系統命令,而未進行任何驗證:
import os
import sys
for arg in sys.argv[1:]:
os.system(arg)
在上述程式碼中,使用者輸入的引數被直接傳遞給os.system()方法,這可能導致惡意命令的執行。為了避免這種情況,應用程式應該實施嚴格的輸入驗證和清理機制。
另一個範例是使用print函式輸出使用者控制的變數filename,而未進行任何驗證:
import os
import sys
filename = sys.argv[1]
if os.path.isfile(filename):
print(filename, 'exists')
else:
print(filename, 'not found')
內容解密:
sys.argv[1]取得命令列的第一個引數,並將其指定給filename變數。os.path.isfile(filename)檢查filename是否為一個存在的檔案。- 根據檢查結果輸出相應的訊息。
- 此處的安全風險在於
filename未經驗證,可能包含惡意輸入。
eval()函式的安全性問題
Python的eval()函式允許執行字串形式的Python程式碼。如果允許未經信任的輸入,則可能導致惡意程式碼的執行。以下範例展示瞭如何利用eval()函式執行惡意程式碼:
import os
try:
eval("__import__('os').system('clear')", {})
print("Module OS loaded by eval")
except Exception as exception:
print(repr(exception))
內容解密:
eval()函式執行字串形式的Python程式碼。"__import__('os').system('clear')"是一段惡意程式碼,它匯入os模組並執行clear命令。- 傳遞一個空字典作為
globals引數,嘗試限制eval()的執行環境。 - 由於未定義
__builtins__,因此仍可執行__import__函式。
限制eval()函式的執行環境
為了提高安全性,可以透過傳遞globals和locals引數來限制eval()函式的執行環境。例如,透過傳遞一個空字典作為globals引數,可以防止存取全域變數:
>>> eval("os.system('clear')", {})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
NameError: name 'os' is not defined
內容解密:
- 傳遞一個空字典作為
globals引數,限制了eval()函式的執行環境。 - 由於未定義
os模組,因此丟擲NameError例外。
進一步地,可以透過停用內建函式來增強安全性:
>>> eval("__import__('os').system('clear')", {'__builtins__':{}})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
NameError: name '__import__' is not defined
內容解密:
- 停用內建函式後,
__import__函式不可用,因此丟擲NameError例外。 - 這樣可以防止惡意程式碼的執行。
探索Python模組中的安全問題
在Python應用程式中,動態評估程式碼的主要方法是使用eval()和exec函式。然而,這些方法的使用可能導致資料完整性的喪失,並經常導致任意程式碼的執行。為了控制這種情況,我們可以使用正規表示式與re模組來驗證使用者輸入。
控制使用者輸入在動態程式碼評估中的重要性
以下是一個簡單的範例,展示瞭如何使用正規表示式驗證使用者輸入:
import re
python_code = input()
pattern = re.compile("valid_input_regular_expressions")
if pattern.fullmatch(python_code):
eval(python_code)
內容解密:
import re:匯入正規表示式模組,用於驗證輸入是否符合預期格式。python_code = input():接收使用者輸入的Python程式碼。pattern = re.compile("valid_input_regular_expressions"):編譯一個正規表示式模式,用於匹配有效的輸入。if pattern.fullmatch(python_code)::檢查使用者輸入是否完全符合預期的模式。eval(python_code):如果輸入有效,則評估輸入的Python程式碼。
從安全的角度來看,如果使用者輸入在未經驗證的情況下被傳遞給eval(),指令碼可能會容易受到任意程式碼執行的攻擊。想像一下在持有機密資訊的伺服器上執行上述指令碼。攻擊者可能會根據多種因素(如存取許可權)存取這些敏感資訊。
作為eval()函式的替代方案,我們有literal_eval()函式,它屬於ast模組,允許我們以安全的方式評估表示式或Python字串。所提供的字串只能包含Python中的以下資料結構:字串、位元組、數字、元組、列表、字典、集合或布林值。
Pickle模組的安全性
Pickle模組用於實作特定的二進位協定,用於序列化和反序列化Python物件結構。Pickle允許將Python中的物件儲存在檔案中,以便稍後還原。這個模組對於儲存不需要資料函式庫或臨時資料的任何內容都很有用。
序列化範例
import pickle
object_list = ['mastering', 'python', 'security']
with open('data.pickle', 'wb') as file:
pickle.dump(object_list, file)
內容解密:
import pickle:匯入Pickle模組,用於物件的序列化和反序列化。object_list = ['mastering', 'python', 'security']:定義一個列表物件,用於演示序列化。with open('data.pickle', 'wb') as file::以二進位寫入模式開啟一個名為data.pickle的檔案。pickle.dump(object_list, file):將object_list序列化並寫入到開啟的檔案中。
從安全形度來看,Pickle與eval()函式有相同的限制,因為它允許使用者構建執行任意程式碼的輸入。官方檔案警告說,Pickle模組不能保證安全性。事實上,反序列化可以執行任意程式碼。Pickle模組在安全性方面的主要問題包括:
- 對資料/物件完整性沒有控制
- 對資料大小或系統限制沒有控制
- 程式碼在沒有安全控制的情況下被評估
- 字串在沒有驗證的情況下被編碼/解碼
一旦應用程式反序列化不受信任的資料,這可以用來修改應用程式的邏輯或執行任意程式碼。當使用者輸入在傳遞給pickle.load()或pickle.loads()等方法之前沒有被正確地清理和驗證時,就存在弱點。
安全的最佳實踐
從安全形度來看,目前的最佳實踐是絕不從不受信任的輸入源載入資料。您可以使用替代的資料序列化格式,如JSON,或更安全的方法,如yaml.safe_load()。
yaml.load()和yaml.safe_load()之間的主要區別在於,yaml.load()將YAML檔案轉換為Python物件,而yaml.safe_load()將此轉換限制為簡單的Python物件,如整數或列表,如果嘗試開啟包含可執行程式碼的YAML,則會丟擲異常。