隨著網路應用程式日益複雜,安全性議題也越發重要。本文深入探討 Python 網路安全,涵蓋套件管理、YAML、XML 和 HTTP 安全防護等導向。我們將探討如何使用 Pipenv 確保套件依賴的安全性,並示範如何利用 PyYAML 和 defusedxml 安全地解析 YAML 和 XML 檔案,避免潛在的程式碼注入風險。此外,本文也將探討 HTTP 相關的攻擊,例如 DoS 攻擊、Host header 攻擊和開放重定向攻擊,並提供相應的防禦策略與最佳實務,以提升 Python 網路應用程式的安全性。
shell 引數
在某些情況下,可能需要使用 shell 來執行命令。subprocess
模組提供了一個 shell
引數,可以用來啟用 shell 模式。然而,啟用 shell 模式會增加安全風險,因為它允許攻擊者提交惡意命令。
執行命令的安全性
執行命令的安全性取決於多個因素,包括命令本身、命令的引數以及執行命令的環境。為了確保安全性,應該盡可能避免使用 shell 模式,並且應該驗證所有的輸入資料。
13 不要相信輸入
本章涵蓋以下主題:
- 使用 Pipenv 驗證 Python 依賴項
- 使用 PyYAML 安全地解析 YAML
- 使用 defusedxml 安全地解析 XML
- 防止 DoS 攻擊、Host header 攻擊、開放重定向和 SQL 注入
在本章中,Mallory 對 Alice、Bob 和 Charlie 進行了一系列攻擊。這些攻擊和其對策並不複雜,每個攻擊都遵循一個模式:Mallory 使用惡意輸入來濫用系統或使用者。這些攻擊可以以多種形式出現,包括套件依賴項、YAML、XML、HTTP 和 SQL。這些攻擊的目標包括資料損壞、許可權提升和未經授權的資料存取。輸入驗證是預防這些攻擊的解藥。
13.1 使用 Pipenv 進行套件管理
在本節中,我將向您展示如何使用 Pipenv 防止注入攻擊。雜湊和資料完整性等主題將再次出現。像任何 Python 套件管理器一樣,Pipenv 從套件倉函式庫(如 PyPI)檢索和安裝第三方套件。然而,程式設計師們不幸地忽略了這一點:當您使用 Pipenv 安裝套件時,您實際上是在信任套件的作者。
包管理安全:抵禦惡意軟體攻擊
在軟體開發中,包管理是一個非常重要的環節。開發者經常需要從包倉函式庫中下載和安裝各種依賴包,以便實作特定的功能。然而,這個過程也存在著安全風險。假設有一個惡意的攻擊者 Mallory,他可以攻擊包倉函式庫,修改依賴包中的程式碼,然後將惡意程式碼下載到開發者的本地環境中。
包管理安全威脅
包管理安全威脅是一種常見的安全問題。攻擊者可以透過以下方式實作惡意攻擊:
- 包倉函式庫攻擊:攻擊者可以攻擊包倉函式庫,修改依賴包中的程式碼,然後將惡意程式碼下載到開發者的本地環境中。
- 依賴包攻擊:攻擊者可以修改依賴包中的程式碼,然後將惡意程式碼下載到開發者的本地環境中。
Pipenv 的安全機制
Pipenv 是一個 Python 的包管理工具,它提供了一些安全機制來防止惡意攻擊。其中包括:
- 包完整性驗證:Pipenv 可以驗證包的完整性,確保包沒有被修改過。
- 雜湊值驗證:Pipenv 可以驗證包的雜湊值,確保包的內容沒有被修改過。
Pipenv 的雜湊值驗證機制
Pipenv 的雜湊值驗證機制是透過以下步驟實作的:
- 第一次下載包:當 Pipenv第一次下載一個包時,它會計算包的雜湊值,並將雜湊值儲存到
Pipfile.lock
檔案中。 - 後續下載包:當 Pipenv 後續下載同一個包時,它會計算包的雜湊值,並將雜湊值與
Pipfile.lock
檔案中的雜湊值進行比較。如果雜湊值匹配,則 Pipenv 可以確保包沒有被修改過。
示例
以下是 Pipenv 的雜湊值驗證機制的示例:
$ pipenv install
Installing dependencies from Pipfile.lock
An error occurred while installing requests==2.24.0
--hash=sha256:b3559a131db72c33ee969480840fff4bb6dd1117c8...
--hash=sha256:fe75cc94a9443b9246fc7049224f756046acb93f87...
...
[pipenv.exceptions.InstallError]: ['ERROR: THESE PACKAGES DO NOT
MATCH THE HASHES FROM THE REQUIREMENTS FILE. If you have updated
the package versions, please update the hashes. Otherwise,
examine the package contents carefully; someone may have
tampered with them.']
在這個示例中,Pipenv 下載了 requests
包,並計算了包的雜湊值。然後,它將雜湊值與 Pipfile.lock
檔案中的雜湊值進行比較。如果雜湊值不匹配,Pipenv 會報錯,並提示使用者檢查包的內容。
圖表翻譯:
graph LR A[包倉函式庫] -->|攻擊|> B[惡意攻擊者] B -->|修改依賴包|> C[依賴包] C -->|下載|> D[開發者本地環境] D -->|驗證|> E[Pipenv] E -->|雜湊值驗證|> F[包完整性驗證] F -->|透過|> G[包安裝] F -->|不透過|> H[報錯]
這個圖表展示了 Pipenv 的包管理安全機制,包括包倉函式庫攻擊、依賴包攻擊、包完整性驗證和雜湊值驗證等步驟。
YAML 遠端程式碼執行攻擊
在第 7 章中,您看到 Mallory 進行了一次遠端程式碼執行攻擊。她首先將惡意程式碼嵌入到序列化的 Python 物件中,然後將其偽裝成根據 Cookie 的 HTTP 會話狀態並傳送到伺服器。伺服器接收到這個請求後,不經意地執行了惡意程式碼。這次,我們將探討如何使用 YAML 格式來進行類似的攻擊。
安全性注意事項
在撰寫本文時,非安全的反序列化是目前網路安全領域中的一個重大問題。YAML、JSON、CSV 和 XML 都是常見的用於表示資料的格式,每種程式語言都有工具可以解析、序列化和反序列化這些格式。Python 程式設計師經常使用 PyYAML 來解析 YAML。
安裝 PyYAML
要使用 PyYAML,首先需要安裝它。您可以在虛擬環境中使用 pipenv 來安裝 PyYAML:
$ pipenv install pyyaml
解析 YAML 檔案
接下來,讓我們在 Python 中解析一個 YAML 檔案。以下是使用 PyYAML 解析 YAML 檔案的範例:
import yaml
# 定義 YAML 檔案內容
document = """
title: 全面掌握 Python 安全
characters:
- Alice
- Bob
- Charlie
- Eve
- Mallory
"""
# 使用 BaseLoader 解析 YAML 檔案
book = yaml.load(document, Loader=yaml.BaseLoader)
# 存取 YAML 檔案中的資料
print(book['title']) # 輸出:全面掌握 Python 安全
print(book['characters']) # 輸出:['Alice', 'Bob', 'Charlie', 'Eve', 'Mallory']
最小許可權原則
在第 1 章中,您學習了最小許可權原則(PLP)。PLP 指出,使用者或系統應該只被授予執行其職責所需的最小許可權。在這裡,我們將展示如何將 PLP 應用於解析 YAML 檔案。
PyYAML 的 Loader
PyYAML 支援四種不同的 Loader,從最不強大到最強大:
- BaseLoader:支援基本的 Python 物件,如字串和列表。
- SafeLoader:支援基本的 Python 物件和標準 YAML 標籤。
- Loader:支援更多功能,但也增加了風險。
- FullLoader:支援所有 YAML 功能,但也存在最大的風險。
您可以使用 Loader
引數來指定 PyYAML 使用哪種 Loader 來解析 YAML 檔案。例如,以下範例使用 BaseLoader
來解析 YAML 檔案:
book = yaml.load(document, Loader=yaml.BaseLoader)
圖表翻譯:
flowchart TD A[PyYAML] --> B[Loader] B --> C[BaseLoader] C --> D[SafeLoader] D --> E[Loader] E --> F[FullLoader] F --> G[風險增加]
在這個圖表中,我們展示了 PyYAML 的四種 Loader,從最不強大到最強大。每種 Loader 都支援更多功能,但也增加了風險。因此,選擇合適的 Loader 來解析 YAML 檔案非常重要。
XML 實體擴充套件攻擊
XML 實體擴充套件是一種小眾的 XML 特性,允許使用者定義和命名任意資料在 XML 檔案中。這種特性可以被用來實作實體參照,從而在 XML 檔案中嵌入實體。XML 解析器的工作是將實體參照擴充套件為實體。
以下是 Python 程式碼示例,展示了 XML 實體擴充套件的工作原理:
from xml.etree.ElementTree import fromstring
# 定義一個小型的 XML 檔案,包含一個實體宣告和兩個實體參照
xml_doc = '''
<root>
<name>&alice;</name>
<age>25</age>
<name>&alice;</name>
</root>
'''
# 定義實體宣告
entity_decl = '''
<!ENTITY alice "Alice">
'''
# 將實體宣告和 XML 檔案合併
xml_doc = entity_decl + xml_doc
# 解析 XML 檔案
root = fromstring(xml_doc)
# 印出 XML 檔案中的資料
print(root.find('name').text) # 輸出:Alice
print(root.find('age').text) # 輸出:25
print(root.find('.//name[2]').text) # 輸出:Alice
在這個例子中,我們定義了一個小型的 XML 檔案,包含一個實體宣告 &alice;
,它參照了一個名為 alice
的實體。XML 檔案中包含兩個實體參照 &alice;
,它們會被解析器擴充套件為實體 alice
。
實體擴充套件攻擊
實體擴充套件攻擊是指攻擊者利用 XML 實體擴充套件特性,將大量資料嵌入 XML 檔案中,從而導致系統耗盡記憶體。這種攻擊方式可以用來實作拒絕服務(DoS)攻擊。
以下是 Python 程式碼示例,展示了實體擴充套件攻擊的工作原理:
from xml.etree.ElementTree import fromstring
# 定義一個小型的 XML 檔案,包含一個實體宣告和多個實體參照
xml_doc = '''
<root>
<name>&alice;</name>
<age>25</age>
<name>&alice;</name>
<name>&alice;</name>
...
</root>
'''
# 定義實體宣告
entity_decl = '''
<!ENTITY alice "Alice">
'''
# 將實體宣告和 XML 檔案合併
xml_doc = entity_decl + xml_doc
# 解析 XML 檔案
root = fromstring(xml_doc)
# 印出 XML 檔案中的資料
print(root.find('name').text) # 輸出:Alice
print(root.find('age').text) # 輸出:25
print(root.find('.//name[2]').text) # 輸出:Alice
在這個例子中,我們定義了一個小型的 XML 檔案,包含一個實體宣告 &alice;
,它參照了一個名為 alice
的實體。XML 檔案中包含多個實體參照 &alice;
,它們會被解析器擴充套件為實體 alice
。這會導致系統耗盡記憶體。
圖表翻譯:
graph LR A[XML 檔案] --> B[實體宣告] B --> C[實體參照] C --> D[解析器] D --> E[記憶體耗盡] E --> F[拒絕服務攻擊]
這個圖表展示了實體擴充套件攻擊的工作原理。XML 檔案包含實體宣告和實體參照,解析器會將實體參照擴充套件為實體,從而導致記憶體耗盡和拒絕服務攻擊。
XML 實體擴充套件攻擊
XML 實體擴充套件是一種功能,允許開發人員定義實體並在 XML 檔案中參照它們。然而,這種功能也可以被用來對系統進行攻擊,尤其是在實體定義過大或被過多次參照的情況下。
XML 實體擴充套件示例
以下是一個簡單的 XML 檔案,示範了實體擴充套件的功能:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE example [
<!ENTITY a "Alice">
]>
<root>&a;&a;</root>
在這個例子中,實體 a
被定義為 "Alice"
,然後在 root
元素中被參照兩次。解析這個 XML 檔案後,實體會被擴充套件,結果為 "AliceAlice"
。
二次爆炸攻擊
二次爆炸攻擊是一種利用 XML 實體擴充套件功能對系統進行攻擊的方法。攻擊者可以建立一個 XML 檔案,其中包含一個大型實體和多個對該實體的參照。當系統解析這個 XML 檔案時,實體會被擴充套件,導致系統記憶體使用量急劇增加。
以下是一個示例:
<!DOCTYPE bomb [
<!ENTITY e "a loooooooooooooooooooooooooong entity ...">
]>
<bomb>&e;&e;&e;&e;&e;&e;&e;&e;&e;&e;</bomb>
在這個例子中,實體 e
被定義為一個長字串,然後在 bomb
元素中被參照 10 次。如果實體 e
的大小為 1 MB,則這個 XML 檔案會被擴充套件為 10 MB。
防禦措施
為了防禦二次爆炸攻擊,系統可以實施以下措施:
- 限制 XML 檔案的大小:系統可以設定一個最大允許的 XML 檔案大小,超過這個大小的檔案將被拒絕。
- 限制實體的大小:系統可以設定一個最大允許的實體大小,超過這個大小的實體將被拒絕。
- 限制實體的參照次數:系統可以設定一個最大允許的實體參照次數,超過這個次數的參照將被拒絕。
- 使用安全的 XML 解析器:系統可以使用安全的 XML 解析器,例如那些具有實體擴充套件限制的解析器。
XML攻擊:億笑攻擊和防禦
XML(Extensible Markup Language)是一種用於描述和交換資料的標記語言。然而,XML也可能被用於惡意目的,例如億笑攻擊(Billion Laughs Attack)。這種攻擊是透過建立一個包含大量巢狀實體的XML檔案,從而導致XML解析器耗盡記憶體資源。
億笑攻擊
億笑攻擊是一種特殊的XML攻擊,透過建立一個包含多級巢狀實體的XML檔案,從而導致XML解析器耗盡記憶體資源。以下是一個例子:
<!DOCTYPE bomb [
<!ENTITY a "lol">
<!ENTITY b "&a;&a;&a;&a;&a;&a;&a;&a;&a;&a;">
<!ENTITY c "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;">
<!ENTITY d "&c;&c;&c;&c;&c;&c;&c;&c;&c;&c;">
]>
<bomb>&d;</bomb>
這個XML檔案包含四個巢狀實體:a
、b
、c
和d
。每個實體都包含多個參照其他實體的例項。當XML解析器嘗試解析這個檔案時,它會不斷地展開這些實體,從而導致記憶體資源耗盡。
防禦億笑攻擊
要防禦億笑攻擊,可以使用一個叫做defusedxml
的Python函式庫。這個函式庫提供了一個安全的XML解析器,可以防止億笑攻擊。以下是一個例子:
from defusedxml.ElementTree import parse
try:
parse('/path/to/billion_laughs.xml')
except EntitiesForbidden:
print("億笑攻擊被防禦")
在這個例子中,我們使用defusedxml
函式庫的parse
函式來解析XML檔案。如果檔案包含巢狀實體,parse
函式會引發一個EntitiesForbidden
異常。
Python XML API 和 defusedxml 替代品
以下是Python的XML API和defusedxml的替代品:
Native Python API | defusedxml API |
---|---|
xml.dom.minidom.parse | defusedxml.minidom.parse |
xml.dom.pulldom.parse | defusedxml.pulldom.parse |
xml.sax.parse | defusedxml.sax.parse |
xml.etree.ElementTree.parse | defusedxml.ElementTree.parse |
使用defusedxml
函式庫可以有效地防禦億笑攻擊和其他類似的XML攻擊。
服務拒絕攻擊(DoS)簡介
服務拒絕攻擊(Denial of Service,DoS)是一種設計用來使系統不堪負荷的攻擊,通常是透過大量消耗系統資源來實作的。這些資源包括儲存空間、網路頻寬、CPU等。DoS攻擊的目的是透過使系統過載來拒絕使用者存取服務。
DoS攻擊的型別
DoS攻擊有很多種類,包括但不限於以下幾種:
- 網路流量攻擊:透過向系統傳送大量網路流量來使系統不堪負荷。
- 儲存空間攻擊:透過向系統傳送大量資料來使儲存空間不足。
- CPU攻擊:透過向系統傳送大量計算任務來使CPU過載。
DoS攻擊的防禦
DoS攻擊的防禦需要從多個層面入手,包括:
- 網路層面:使用防火牆、入侵檢測系統等網路安全裝置來過濾和阻止惡意流量。
- 應用層面:使用應用層面的安全措施,例如設定請求引數限制、請求體大小限制等。
Django中的DoS攻擊防禦設定
Django提供了一些設定來幫助防禦DoS攻擊,包括:
- DATA_UPLOAD_MAX_NUMBER_FIELDS:設定最大允許的請求引數數量。
- DATA_UPLOAD_MAX_MEMORY_SIZE:設定最大允許的請求體大小(以位元組為單位)。
以下是Django中相關設定的示例:
# settings.py
DATA_UPLOAD_MAX_NUMBER_FIELDS = 1000
DATA_UPLOAD_MAX_MEMORY_SIZE = 1024 * 1024 # 1MB
防禦DoS攻擊的最佳實踐
- 監控系統:實時監控系統的效能和安全狀態。
- 設定安全措施:設定合適的安全措施,例如防火牆、入侵檢測系統等。
- 更新和維護:定期更新和維護系統和應用程式,以確保安全性和效能。
圖表翻譯:
flowchart TD A[DoS攻擊] --> B[網路流量攻擊] A --> C[儲存空間攻擊] A --> D[CPU攻擊] B --> E[防火牆] C --> F[儲存空間限制] D --> G[CPU限制]
在這個圖表中,我們可以看到DoS攻擊的不同型別和對應的防禦措施。透過設定合適的安全措施和監控系統,我們可以有效地防禦DoS攻擊。
網路安全:抵禦 HTTP 型別的 DoS 攻擊
在網路安全中,抵禦 HTTP 型別的 DoS 攻擊是一個重要的議題。DoS 攻擊(Denial of Service)是指惡意的攻擊者嘗試使網站或服務無法正常運作,通常是透過大量的請求或資料傳輸來達成。以下將介紹一些 Gunicorn 引數,來幫助抵禦這型別的攻擊。
Gunicorn 引數
Gunicorn 提供了多個引數來設定 HTTP 請求的限制,以下是幾個重要的引數:
limit-request-line
:設定 HTTP 請求行的大小限制,包括 HTTP 方法、協定版本和 URL。預設值為 4094,最大值為 8190。設定為 0 可以停用這個限制。limit-request-fields
:設定 HTTP 請求中允許的最大 header 數量。預設值為 100,最大值為 32768。limit-request-field_size
:設定 HTTP header 的最大允許大小。預設值為 8190,設定為 0 可以允許 header 的大小不受限制。
Host Header 攻擊
Host Header 攻擊是一種利用 HTTP 的 Host Header 欄位來進行的攻擊。惡意的攻擊者可以透過設定 Host Header 的值來使得網站將請求轉發到錯誤的位置,從而可能導致安全漏洞。
防禦措施
為了防禦這型別的攻擊,需要設定正確的 Gunicorn 引數,並確保網站的安全設定。以下是一些防禦措施:
- 設定
limit-request-line
、limit-request-fields
和limit-request-field_size
引數,來限制 HTTP 請求的大小和 header 數量。 - 確保網站的安全設定,例如設定正確的 Host Header 欄位,來防禦 Host Header 攻擊。
- 使用安全的網站框架和函式庫,來防禦常見的安全漏洞。
內容解密:
以上內容介紹了 Gunicorn 引數和 Host Header 攻擊的防禦措施。透過設定正確的 Gunicorn 引數和網站安全設定,可以有效地防禦 HTTP 型別的 DoS 攻擊和 Host Header 攻擊。這些設定可以限制 HTTP 請求的大小和 header 數量,從而防禦惡意的攻擊。
圖表翻譯:
以下是 Gunicorn 引數和 Host Header 攻擊的流程圖:
flowchart TD A[HTTP 請求] --> B[Gunicorn 引數] B --> C[限制請求大小和 header 數量] C --> D[防禦 DoS 攻擊] D --> E[防禦 Host Header 攻擊] E --> F[設定正確的 Host Header 欄位] F --> G[確保網站安全設定]
這個流程圖顯示了 Gunicorn 引數和 Host Header 攻擊的防禦措施的流程。透過設定正確的 Gunicorn 引數和網站安全設定,可以有效地防禦 HTTP 型別的 DoS 攻擊和 Host Header 攻擊。
網站安全:Host Header 驗證和 Open Redirect 攻擊
Host Header 驗證
在網站開發中,Host Header 是用於指定請求的主機名稱。然而,直接存取 Host Header 可能會導致安全風險。為了避免這種風險,Django 提供了一個 get_host
方法來驗證和擷取 Host Header。
以下是直接存取 Host Header 的壞實踐:
bad_practice = request.META['HTTP_HOST']
這種做法會繞過輸入驗證,可能導致安全風險。
以下是使用 get_host
方法的好實踐:
good_practice = request.get_host()
這種做法會驗證 Host Header,確保主機名稱是有效的。
ALLOWED_HOSTS 設定
Django 提供了一個 ALLOWED_HOSTS
設定,允許您指定哪些主機名稱可以存取您的網站。這個設定是用於防止 Host Header 攻擊。
以下是 ALLOWED_HOSTS
設定的範例:
ALLOWED_HOSTS = ['example.com', 'www.example.com']
您可以動態地從公鑰證書中擷取主機名稱,然後將其新增到 ALLOWED_HOSTS
設定中。以下是使用 cryptography
套件的範例:
from cryptography.hazmat.backends import default_backend
from cryptography.x509.oid import NameOID
with open(CERTIFICATE_PATH, 'rb') as f:
cert = default_backend().load_pem_x509_certificate(f.read())
ALLOWED_HOSTS = [a.value for a in cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME)]
Open Redirect 攻擊
Open Redirect 攻擊是一種網站安全風險,攻擊者可以將使用者重定向到惡意網站。以下是 Open Redirect 攻擊的範例:
假設 Mallory 想要偷取 Bob 的錢,她可以建立一個網站,模仿 Alice 的線上銀行網站。然後,她可以將 Bob 重定向到她的網站,讓 Bob 輸入他的登入憑證。Mallory 的網站可以使用 Bob 的憑證來存取他的帳戶。
為了防止 Open Redirect 攻擊,網站開發者必須小心地處理重定向。以下是使用 Django 的 redirect
函式的範例:
from django.shortcuts import redirect
def my_view(request):
# ...
return redirect('https://example.com')
在這個範例中,redirect
函式會將使用者重定向到 https://example.com
。然而,如果攻擊者可以控制重定向的 URL,則可能會導致 Open Redirect 攻擊。
為了防止這種風險,網站開發者可以使用 is_safe_url
函式來驗證重定向的 URL。以下是使用 is_safe_url
函式的範例:
from django.utils.http import is_safe_url
def my_view(request):
# ...
url = 'https://example.com'
if is_safe_url(url):
return redirect(url)
else:
# ...
在這個範例中,is_safe_url
函式會驗證重定向的 URL 是否安全。如果 URL 不安全,則會傳回錯誤。
網站安全:抵禦開放重定向攻擊
開放重定向攻擊是一種常見的網路安全威脅,攻擊者可以利用這種漏洞將使用者重定向到惡意網站,以竊取使用者的敏感資訊。這種攻擊通常是透過在網站的URL中加入惡意的重定向引數實作的。
深入剖析網路安全議題,從底層的套件管理到高階的 HTTP 請求,本篇探討了確保應用程式安全的關鍵環節。分析顯示,無論是使用 Pipenv 管理套件、解析 YAML 和 XML 檔案,或是處理 HTTP 請求和重定向,輸入驗證都是抵禦惡意攻擊的第一道防線。忽略輸入驗證的後果,輕則導致程式當機,重則可能造成資料洩露和系統癱瘓。技術堆疊的各層級協同運作中體現,縱深防禦策略的重要性不容忽視。對於重視長期穩定性的企業,採取多層級的防禦策略,包括使用安全的解析器、設定資源限制、驗證所有使用者輸入,並定期更新安全策略,將帶來最佳平衡。玄貓認為,安全意識的提升和最佳實務的落實,才是構建安全可靠應用程式的基本。隨著攻擊手段日趨複雜,持續學習和更新安全知識,才能在不斷變化的威脅態勢中保持領先。