在 Django 專案中,強化網頁安全防護至關重要,尤其需防範惡意程式碼注入攻擊,如跨站指令碼攻擊(XSS)。內容安全政策(CSP)是有效防禦 XSS 的關鍵機制,能限制瀏覽器載入資源的來源,降低攻擊風險。本文將深入探討如何在 Django 中實作 CSP,並運用 django-csp 套件簡化設定流程。

CSP 是一種網頁安全標準,透過定義一系列指令來控制瀏覽器載入資源的行為,有效降低 XSS、程式碼注入等攻擊風險。CSP 主要透過 HTTP 回應標頭中的 Content-Security-Policy 欄位設定,可以針對不同資源型別(例如指令碼、樣式、圖片)設定允許的來源。開發者可以利用 CSP 指令精細控制允許載入的資源,例如限制僅允許載入來自自身網域的指令碼和樣式,或指定可信任的 CDN 網域。

驗證多個表單欄位

在 Django 中,當我們需要驗證多個表單欄位時,可以在表單類別中定義一個 clean 方法。這個方法允許我們存取表單中的所有欄位,並進行跨欄位的驗證。

定義表單類別

首先,我們定義一個表單類別 AuthenticatedMessageForm,它包含兩個欄位:messagehash_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>&lt;script&gt;/* malicious */&lt;/script&gt;</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攻擊。然而,這種防禦機制並非萬無一失,仍需要開發者注意以下幾點:

  1. 使用escape過濾器:Django提供了escape過濾器,可以對使用者輸入的資料進行HTML編碼,防止XSS攻擊。
  2. 使用mark_safe函式:如果需要將使用者輸入的資料作為HTML程式碼輸出,則需要使用mark_safe函式將其標記為安全程式碼。
  3. 注意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回應頭:

  1. Content-Type:指定回應體的MIME型別,可以用來防止XSS攻擊。
  2. X-Content-Type-Options:指定瀏覽器如何處理回應體的MIME型別,可以用來防止XSS攻擊。
  3. 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攻擊?

  1. 輸入驗證:在伺服器端驗證使用者輸入的資料,以防止惡意程式碼被注入。
  2. 輸出編碼:在輸出使用者輸入的資料時,對其進行編碼,以防止瀏覽器將其解釋為程式碼。
  3. 設定適當的HTTP標頭:設定適當的HTTP標頭,例如Content-Security-Policy,以限制瀏覽器可以執行的程式碼。
  4. 使用安全的函式庫和框架:使用安全的函式庫和框架,例如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-srcstyle-srcimg-src指令,僅允許從自身網域載入資源。

內容解密:

上述例子中,我們設定了script-srcstyle-srcimg-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 中新增 CSPMiddlewareMIDDLEWARE 列表中:

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-srcstyle-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 不僅僅是一個安全機制,更是一種安全思維的體現,它促使開發者更深入地思考網頁資源的載入方式和潛在風險,從而構建更安全的網頁應用。