在 Django 專案中,強化網頁安全防護至關重要,尤其需防範惡意程式碼注入攻擊,如跨站指令碼攻擊(XSS)。內容安全政策(CSP)是有效防禦 XSS 的關鍵機制,能限制瀏覽器載入資源的來源,降低攻擊風險。本文將深入探討如何在 Django 中實作 CSP,並運用 django-csp 套件簡化設定流程。
CSP 是一種網頁安全標準,透過定義一系列指令來控制瀏覽器載入資源的行為,有效降低 XSS、程式碼注入等攻擊風險。CSP 主要透過 HTTP 回應標頭中的 Content-Security-Policy
欄位設定,可以針對不同資源型別(例如指令碼、樣式、圖片)設定允許的來源。開發者可以利用 CSP 指令精細控制允許載入的資源,例如限制僅允許載入來自自身網域的指令碼和樣式,或指定可信任的 CDN 網域。
驗證多個表單欄位
在 Django 中,當我們需要驗證多個表單欄位時,可以在表單類別中定義一個 clean
方法。這個方法允許我們存取表單中的所有欄位,並進行跨欄位的驗證。
定義表單類別
首先,我們定義一個表單類別 AuthenticatedMessageForm
,它包含兩個欄位:message
和 hash_value
。
from django import forms
from django.core.validators import RegexValidator
class AuthenticatedMessageForm(forms.Form):
message = forms.CharField(min_length=1, max_length=100)
hash_value = forms.CharField(validators=[RegexValidator(regex='[0-9a-f]{64}')])
在上面的例子中,message
欄位的長度必須在 1 到 100 個字元之間,而 hash_value
欄位必須符合正規表示式 [0-9a-f]{64}
,也就是說它必須是一個 64 個十六進位制字元的字串。
實作 clean 方法
現在,我們可以在表單類別中定義一個 clean
方法,用於驗證多個欄位。
def clean(self):
cleaned_data = super().clean()
message = cleaned_data.get('message')
hash_value = cleaned_data.get('hash_value')
# 進行跨欄位驗證
if message and hash_value:
# 在這裡進行驗證邏輯
pass
在 clean
方法中,我們可以存取所有欄位的值,並進行跨欄位的驗證。
驗證結果
如果驗證失敗,Django 會自動拒絕表單的提交,並顯示錯誤訊息。
14.3 輸出轉義
輸出轉義是防禦跨站指令碼攻擊(XSS)的最有效方法。為什麼輸出轉義如此重要?讓我們想像一下你工作中使用的資料函式庫。想想所有的表格和每個表格中的欄位。很可能,大多數這些欄位在某種程度上會在網頁上顯示。每一個都擴大了攻擊的空間,並且很多都可以透過特殊的HTML符號被用作攻擊工具。
安全的網站透過轉義HTML特殊符號來防禦XSS攻擊。這些符號和它們的轉義版本如下表所示:
特殊符號 | 名稱和描述 | HTML實體(轉義版本) |
---|---|---|
< | 小於,標籤開始 | < |
> | 大於,標籤結束 | > |
' | 單引號,屬性值定義 | ' |
" | 雙引號,屬性值定義 | " |
& | 連字元,實體定義 | & |
就像任何其他網頁框架一樣,Django的範本機制自動轉義輸出,替換特殊符號為它們的HTML實體。例如,如果你從資料函式庫中提取一些資料並在範本中顯示,它不需要擔心持續的XSS攻擊:
<html>
<div>
{{ fetched_from_db }}
</div>
</html>
你也不需要擔心反射XSS漏洞,如果你的範本顯示一個查詢引數:
<html>
<div>
{{ request.GET.query_parameter }}
</div>
</html>
在專案根目錄下開啟Django的互動式shell,輸入以下程式碼來驗證Django的XSS防禦功能:
$ python manage.py shell
>>> from django.template import Template, Context
>>> template = Template('<html>{{ var }}</html>')
>>> poison = '<script>/* malicious */</script>'
>>> ctx = Context({'var': poison})
>>> template.render(ctx)
'<html><script>/* malicious */</script></html>'
這個功能讓你少了很多煩惱,但並不意味著你可以完全忘記XSS。下一節將介紹如何以及何時停用這個功能。
14.3.1 內建顯示工具
Django的範本機制支援多種內建標籤、過濾器和服務函式來顯示HTML標記。內建的autoescape
標籤用於在範本的一部分顯示中明確停用自動特殊符號轉義。當範本機制遇到這個標籤時,它會在其中顯示所有內容而不進行特殊符號轉義,這意味著以下程式碼對XSS攻擊是脆弱的:
<html>
{% autoescape off %}
<div>
{{ request.GET.query_parameter }}
</div>
{% endautoescape %}
</html>
使用autoescape
標籤的合法案例很少且值得懷疑。例如,可能有人決定在資料函式庫中儲存HTML程式碼,而你負責顯示它。這也適用於內建的safe
過濾器,它暫停對範本中單個變數的自動特殊符號轉義。以下程式碼(盡管過濾器名為safe
)對XSS攻擊是脆弱的:
<html>
<div>
{{ request.GET.query_parameter|safe }}
</div>
</html>
警告:safe
過濾器會停用安全機制。我個人認為對它來說,unsafe
可能是一個更好的名字。請小心使用這個過濾器。
safe
過濾器將大部分工作委託給一個名為mark_safe
的內建服務函式。這個函式接受一個Python字串並將其轉換為SafeString
物件。當範本處理器遇到SafeString
時,它會顯示其內容而不進行特殊符號轉義。
將mark_safe
應用於來自不可信任源的資料是一個邀請駭客進入系統的請求。請在Django互動式shell中輸入以下程式碼來瞭解原因。它建立了一個簡單的範本並向其中增加了一個惡意指令碼。指令碼(以粗體顯示)被標記為安全並注入範本中。在結果中,由於不是範本機制的錯誤,所有特殊符號保持不轉義:
$ python manage.py shell
>>> from django.template import Template, Context
>>> from django.utils.safestring import mark_safe
>>> template = Template('<html>{{ var }}</html>')
>>> poison = '<script>/* malicious */</script>'
>>> ctx = Context({'var': mark_safe(poison)})
>>> template.render(ctx)
'<html><script>/* malicious */</script></html>'
XSS攻擊防禦
什麼是XSS攻擊?
XSS(Cross-Site Scripting)是一種網頁攻擊,攻擊者將惡意的JavaScript程式碼注入到網頁中,當使用者瀏覽網頁時,瀏覽器會執行這些惡意程式碼,從而實作攻擊者的惡意目的。
Django範本引擎的XSS防禦
Django的範本引擎具有內建的XSS防禦機制,可以自動對使用者輸入的資料進行HTML編碼,防止XSS攻擊。然而,這種防禦機制並非萬無一失,仍需要開發者注意以下幾點:
- 使用
escape
過濾器:Django提供了escape
過濾器,可以對使用者輸入的資料進行HTML編碼,防止XSS攻擊。 - 使用
mark_safe
函式:如果需要將使用者輸入的資料作為HTML程式碼輸出,則需要使用mark_safe
函式將其標記為安全程式碼。 - 注意HTML屬性:如果需要將使用者輸入的資料作為HTML屬性值,則需要注意HTML屬性的特殊字元,例如引號和尖括號。
屬性封裝
在HTML中,屬性值應該被封裝在引號中,以防止XSS攻擊。例如:
<div class="{{ request.GET.query_parameter }}">
應該改為:
<div class="{{ request.GET.query_parameter|escape }}">
或者:
<div class="{{ request.GET.query_parameter|safe }}">
HTTP回應頭
HTTP回應頭也可以被用來防禦XSS攻擊。以下是幾種常見的HTTP回應頭:
Content-Type
:指定回應體的MIME型別,可以用來防止XSS攻擊。X-Content-Type-Options
:指定瀏覽器如何處理回應體的MIME型別,可以用來防止XSS攻擊。X-XSS-Protection
:指定瀏覽器是否啟用XSS防禦機制,可以用來防止XSS攻擊。
網站安全:保護使用者免受跨站指令碼攻擊(XSS)
跨站指令碼攻擊(XSS)是一種網站安全漏洞,允許攻擊者注入惡意指令碼,竊取使用者資料或進行其他惡意行為。為了保護使用者免受XSS攻擊,網站開發者可以採取以下幾種措施:
1. 設定HttpOnly旗標
設定HttpOnly旗標可以防止JavaScript存取cookie,從而減少XSS攻擊的風險。HttpOnly旗標是一個特殊的旗標,可以設定在cookie中,當設定了HttpOnly旗標後,JavaScript就無法存取cookie。
2. 啟用XSS過濾
啟用XSS過濾可以幫助過濾掉惡意指令碼,防止XSS攻擊。XSS過濾是一種技術,可以自動偵測和過濾掉惡意指令碼,從而保護使用者免受XSS攻擊。
3. 使用內容安全政策(CSP)
內容安全政策(CSP)是一種安全機制,可以幫助防止XSS攻擊。CSP可以設定允許的內容來源,從而防止惡意指令碼注入。
4. 驗證使用者輸入
驗證使用者輸入可以幫助防止XSS攻擊。當使用者輸入資料時,應該驗證輸入的資料是否合法,從而防止惡意指令碼注入。
5. 更新軟體和外掛
更新軟體和外掛可以幫助修復已知的安全漏洞,從而減少XSS攻擊的風險。
內容解密:
- 設定HttpOnly旗標可以防止JavaScript存取cookie。
- 啟用XSS過濾可以幫助過濾掉惡意指令碼。
- 使用內容安全政策(CSP)可以設定允許的內容來源。
- 驗證使用者輸入可以幫助防止XSS攻擊。
- 更新軟體和外掛可以幫助修復已知的安全漏洞。
flowchart TD A[設定HttpOnly旗標] --> B[啟用XSS過濾] B --> C[使用內容安全政策(CSP)] C --> D[驗證使用者輸入] D --> E[更新軟體和外掛]
圖表翻譯:
此圖表示了保護使用者免受跨站指令碼攻擊(XSS)的步驟。首先,設定HttpOnly旗標可以防止JavaScript存取cookie。接下來,啟用XSS過濾可以幫助過濾掉惡意指令碼。然後,使用內容安全政策(CSP)可以設定允許的內容來源。之後,驗證使用者輸入可以幫助防止XSS攻擊。最後,更新軟體和外掛可以幫助修復已知的安全漏洞。
網頁安全:瞭解XSS攻擊與防禦
什麼是XSS攻擊?
XSS(Cross-Site Scripting)是一種網頁安全漏洞,允許攻擊者在網頁中注入惡意指令碼,從而控制使用者的瀏覽器行為。XSS攻擊可以分為三種型別:儲存型XSS、反射型XSS和DOM型XSS。
如何防禦XSS攻擊?
- 輸入驗證:在伺服器端驗證使用者輸入的資料,以防止惡意程式碼被注入。
- 輸出編碼:在輸出使用者輸入的資料時,對其進行編碼,以防止瀏覽器將其解釋為程式碼。
- 設定適當的HTTP標頭:設定適當的HTTP標頭,例如
Content-Security-Policy
,以限制瀏覽器可以執行的程式碼。 - 使用安全的函式庫和框架:使用安全的函式庫和框架,例如Django,來開發網頁應用程式。
Content-Security-Policy(CSP)
CSP是一種安全機制,允許網頁設定限制瀏覽器可以執行的程式碼。CSP可以透過設定HTTP標頭Content-Security-Policy
來實作。
CSP指令
CSP指令包括:
script-src
:指定允許執行的指令碼來源。style-src
:指定允許執行的樣式表來源。img-src
:指定允許載入的圖片來源。object-src
:指定允許載入的物件來源。
CSP範例
Content-Security-Policy: script-src 'self' https://example.com;
這個範例指定允許執行來自自身網域名稱和https://example.com
的指令碼。
政策:內容安全性政策(CSP)基礎知識
什麼是內容安全性政策(CSP)?
內容安全性政策(CSP)是一種安全機制,旨在防止跨站指令碼攻擊(XSS)。它允許網站指定哪些內容源可以被瀏覽器載入和執行,從而減少XSS攻擊的風險。
CSP 的工作原理
CSP 透過指定一系列指令來控制瀏覽器對內容的載入和執行。這些指令包括:
default-src
:指定瀏覽器對於未明確指定的內容源的預設行為。script-src
:指定瀏覽器可以載入和執行的JavaScript程式碼的來源。style-src
:指定瀏覽器可以載入和應用的CSS樣式表的來源。
CSP 的指令
CSP 的指令可以用來控制瀏覽器對於不同型別內容的載入和執行。以下是一些常見的指令:
default-src 'self'
:指定瀏覽器只允許載入和執行來自相同源的內容。script-src 'nonce-EKpb5h6TajmKa5pK'
:指定瀏覽器只允許載入和執行具有指定nonce值的JavaScript程式碼。style-src 'self'
:指定瀏覽器只允許載入和應用來自相同源的CSS樣式表。
CSP 的優點
CSP 可以幫助防止XSS攻擊,減少網站被攻擊的風險。它還可以幫助網站開發者控制瀏覽器對於內容的載入和執行,提高網站的安全性。
CSP 的實施
要實施CSP,網站開發者需要在網站的HTTP回應頭中新增CSP指令。以下是一個例子:
Content-Security-Policy: default-src 'self'; script-src 'nonce-EKpb5h6TajmKa5pK'; style-src 'self'
這個例子指定了瀏覽器只允許載入和執行來自相同源的內容,JavaScript程式碼需要具有指定的nonce值,CSS樣式表需要來自相同源。
根據提供的內容,以下是根據玄貓(BlackCat)技術內容系統指引重寫的技術文章:
網頁安全:內容安全政策(CSP)
內容安全政策(CSP)是一種強大的工具,幫助保護網頁免受跨站指令碼攻擊(XSS)和其他安全威脅。透過設定適當的CSP指令,可以限制網頁中可執行的內容,從而提高網頁的安全性。
CSP指令
CSP指令分為兩大類別:資源載入指令和導航指令。資源載入指令用於控制網頁中可載入的資源,例如圖片、指令碼和樣式表。導航指令則用於控制網頁的導航行為,例如表單提交和框架導航。
資源載入指令
script-src
:控制可執行的指令碼來源。style-src
:控制可應用的樣式表來源。img-src
:控制可載入的圖片來源。object-src
:控制可載入的物件來源,例如Flash和Java。media-src
:控制可載入的多媒體來源,例如音訊和影片。frame-src
:控制可載入的框架來源。font-src
:控制可載入的字型來源。connect-src
:控制可連線的來源,例如WebSocket和XMLHttpRequest。
導航指令
form-action
:控制可提交的表單來源。frame-ancestors
:控制可導航的框架來源。
CSP實施
實施CSP相對簡單,只需在網頁的HTTP回應頭中新增Content-Security-Policy
欄位,並設定適當的指令即可。例如:
Content-Security-Policy: script-src 'self'; style-src 'self'; img-src 'self';
這個例子設定了script-src
、style-src
和img-src
指令,僅允許從自身網域載入資源。
內容解密:
上述例子中,我們設定了script-src
、style-src
和img-src
指令,僅允許從自身網域載入資源。這意味著,如果有一個惡意指令碼試圖從其他網域載入資源,瀏覽器將會阻止這個動作,從而保護網頁的安全性。
圖表翻譯:
以下是CSP指令的Mermaid圖表:
graph LR A[script-src] --> B['self'] A --> C[style-src] A --> D[img-src] B --> E[允許從自身網域載入資源] C --> F[允許從自身網域載入樣式表] D --> G[允許從自身網域載入圖片]
這個圖表展示了CSP指令之間的關係,以及如何設定指令以限制網頁中可執行的內容。
使用 django-csp 佈署內容安全政策
要佈署內容安全政策,可以使用 django-csp 進行快速設定。首先,需要在虛擬環境中安裝 django-csp:
pipenv install django-csp
然後,需要在 settings.py
中新增 CSPMiddleware
到 MIDDLEWARE
列表中:
MIDDLEWARE = [
#...
'csp.middleware.CSPMiddleware',
#...
]
CSPMiddleware
會在每個回應中新增 Content-Security-Policy
標頭。這個標頭有許多設定選項,以下是幾個重要的設定:
CSP_DEFAULT_SRC
CSP_DEFAULT_SRC
用於設定預設的源列表。這個設定可以是一個元組或列表,包含一個或多個源。例如:
CSP_DEFAULT_SRC = ("'self'", )
這個設定允許瀏覽器從同源(self)載入資源。
CSP_INCLUDE_NONCE_IN
CSP_INCLUDE_NONCE_IN
用於設定需要包含 nonce 的指令。nonce 是一個隨機生成的字串,用於防止跨站指令碼攻擊(XSS)。例如:
CSP_INCLUDE_NONCE_IN = ['script-src', 'style-src', ]
這個設定允許瀏覽器獨立地處理內嵌指令碼和樣式表,並且會在每個內嵌指令碼和樣式表中新增 nonce 屬性。
取得有效的 nonce
要在範本中使用 nonce,可以使用 request.csp_nonce
屬性。例如:
<script nonce='{{ request.csp_nonce }}'>
/* 內嵌指令碼 */
</script>
<style nonce='{{ request.csp_nonce }}'>
body {
font-size: 42;
}
</style>
設定 script-src 和 style-src
如果你已經設定了 script-src
和 style-src
指令,瀏覽器就不會再使用 default-src
。因此,你需要明確地要求 django-csp 傳送這些指令,同時包含 self 和 nonce 的源。例如:
CSP_SCRIPT_SRC = ("'self'", )
CSP_STYLE_SRC = ("'self'", )
設定 CDN
如果你需要從 CDN 載入資源,可以新增以下設定:
CSP_SCRIPT_SRC = ("'self'", "https://cdn.example.com")
CSP_STYLE_SRC = ("'self'", "https://cdn.example.com")
設定導航指令
最後,需要設定導航指令,例如:
CSP_FORM_ACTION = ("'self'", )
CSP_FRAME_ANCESTORS = ("'none'", )
重新啟動 Django 專案,並使用 Python 的互動式 shell 測試 CSP 標頭:
import requests
response = requests.get('https://example.com')
print(response.headers['Content-Security-Policy'])
這將顯示包含六個指令的 CSP 標頭。
使用個體化政策
在 Django 中,使用 django-csp
套件可以定義個體化的 Content Security Policy (CSP) 政策,以滿足不同資源的需求。這個套件提供了裝飾器(decorator),可以用來修改或替換個別檢視(view)的 CSP 政策。
個體化政策的優點
使用個體化政策可以幫助您處理特殊情況,例如當您需要載入外部資源(如 Google 的字型或樣式表)時。這些資源可能不符合您的全域 CSP 政策,但您仍然需要載入它們。
實際範例
假設您有一個網頁需要載入 Google 的字型和樣式表。您可以使用 csp_update
裝飾器來定義個體化的 CSP 政策,以允許載入這些資源。
from csp.decorators import csp_update
@csp_update(
style_src=['https://fonts.googleapis.com'],
font_src=['https://fonts.gstatic.com']
)
class CspUpdateView(View):
def get(self, request):
# 網頁內容
return render(request, 'template.html')
在這個範例中,csp_update
裝飾器用來定義個體化的 CSP 政策,允許載入 Google 的字型和樣式表。這個政策只適用於 CspUpdateView
檢視,不會影響全域的 CSP 政策。
使用 csp_update
裝飾器
csp_update
裝飾器可以用來定義個體化的 CSP 政策。它接受多個引數,包括:
style_src
: 定義樣式表的來源font_src
: 定義字型的來源script_src
: 定義指令碼的來源object_src
: 定義物件的來源media_src
: 定義媒體的來源frame_src
: 定義框架的來源
您可以使用這些引數來定義個體化的 CSP 政策,以滿足不同資源的需求。
使用 Django-csp 來保護您的網站免受 XSS 攻擊
Django-csp 是一個 Django 的 middleware,幫助您保護您的網站免受 XSS(Cross-Site Scripting)攻擊。它透過設定 Content Security Policy(CSP)來限制瀏覽器可以載入的內容。
CSP 的基本概念
CSP 是一個安全標準,定義了瀏覽器可以載入哪些內容。它透過設定一系列的指令來限制瀏覽器的行為。例如,您可以設定 default-src
指令來指定瀏覽器可以載入的內容的預設源。
使用 Django-csp 來設定 CSP
Django-csp 提供了一個簡單的方式來設定 CSP。您可以在您的 Django 專案中安裝 django-csp,然後在您的設定檔中設定 CSP 的指令。
# settings.py
CSP_DEFAULT_SRC = ("'self'",)
CSP_SCRIPT_SRC = ("'self'",)
CSP_STYLE_SRC = ("'self'",)
使用 Decorator 來設定 CSP
Django-csp 也提供了一個 decorator 來設定 CSP。您可以使用 @csp
decorator 來設定 CSP 的指令。
# views.py
from csp.decorators import csp
@csp(DEFAULT_SRC="'self'")
def my_view(request):
#...
return render(request, 'my_template.html')
報告 CSP 違規
Django-csp 也提供了一個方式來報告 CSP 違規。您可以設定 CSP_REPORT_URI
來指定報告 CSP 違規的 URI。
# settings.py
CSP_REPORT_URI = ('/csp_report/',)
內容解密:
CSP_DEFAULT_SRC
: 指定瀏覽器可以載入的內容的預設源。CSP_SCRIPT_SRC
: 指定瀏覽器可以載入的指令碼源。CSP_STYLE_SRC
: 指定瀏覽器可以載入的樣式源。@csp
: 一個 decorator 來設定 CSP 的指令。CSP_REPORT_URI
: 指定報告 CSP 違規的 URI。
圖表翻譯:
flowchart TD A[設定 CSP] --> B[限制瀏覽器可以載入的內容] B --> C[保護網站免受 XSS 攻擊] C --> D[報告 CSP 違規]
這個圖表展示了使用 Django-csp 來設定 CSP、限制瀏覽器可以載入的內容、保護網站免受 XSS 攻擊和報告 CSP 違規的流程。
第15章:內容保護政策(CSP)
內容保護政策(Content Security Policy, CSP)是一種網頁安全機制,旨在防止跨站指令碼攻擊(Cross-Site Scripting, XSS)和其他型別的攻擊。CSP允許網站定義哪些來源的內容可以被載入和執行,從而有效地防止惡意指令碼的注入。
從技術架構視角來看,內容安全政策(CSP)提供了一個強大的機制,有效降低了XSS、Clickjacking等網頁安全風險。透過定義網頁允許載入資源的來源,CSP限制了惡意指令碼的執行空間,提升了網頁應用的整體安全性。然而,設定過於嚴格的CSP策略可能會影響網頁的正常功能,需要開發者仔細權衡安全性和功能性之間的平衡。例如,過度限制script-src
可能導致網頁依賴的第三方JavaScript函式庫無法正常載入。此外,整合CSP需要考量現有系統架構和資源載入方式,並進行相應調整,例如使用nonce或hash值來允許特定內嵌指令碼的執行。展望未來,隨著瀏覽器對CSP 3.0支援的日漸成熟,更精細化的策略控制和報告機制將進一步提升CSP的實用性和安全性。對於重視安全性的網站,及早匯入CSP並逐步調整策略,將是提升網站安全性的關鍵策略。玄貓認為,CSP 不僅僅是一個安全機制,更是一種安全思維的體現,它促使開發者更深入地思考網頁資源的載入方式和潛在風險,從而構建更安全的網頁應用。