中介層

本文說明 Django 隨附的所有中介層元件。有關如何使用它們以及如何編寫自己的中介層的資訊,請參閱中介層使用指南

可用的中介層

快取中介層

class UpdateCacheMiddleware[原始碼]
class FetchFromCacheMiddleware[原始碼]

啟用全站快取。如果啟用這些快取,每個由 Django 驅動的頁面將快取與 CACHE_MIDDLEWARE_SECONDS 設定定義的時間一樣長。請參閱快取文件

「常用」中介層

class CommonMiddleware[原始碼]
response_redirect_class

預設為 HttpResponsePermanentRedirect。繼承 CommonMiddleware 並覆寫屬性以自訂中介層發出的重新導向。

為完美主義者增加一些便利性

  • 禁止存取DISALLOWED_USER_AGENTS 設定中的使用者代理程式,此設定應為已編譯的正規表示式物件的列表。

  • 根據 APPEND_SLASHPREPEND_WWW 設定執行 URL 重寫。

    如果 APPEND_SLASHTrue,且初始 URL 未以斜線結尾,且在 URLconf 中找不到,則會將斜線附加到結尾來形成新的 URL。如果此新 URL 在 URLconf 中找到,則 Django 會將請求重新導向到此新 URL。否則,初始 URL 會照常處理。

    例如,如果您沒有 foo.com/bar 的有效 URL 模式,但 foo.com/bar/ 的有效模式,則 foo.com/bar 將重新導向至 foo.com/bar/

    如果 PREPEND_WWWTrue,則缺少前導「www.」的 URL 將重新導向至具有前導「www.」的相同 URL。

    這兩個選項都旨在標準化 URL。其理念是每個 URL 都應存在於一個且僅一個位置。從技術上講,URL foo.com/barfoo.com/bar/ 不同 – 搜尋引擎索引器會將它們視為不同的 URL – 因此最佳做法是標準化 URL。

    如有必要,可以使用 no_append_slash() 修飾器將個別視圖排除在 APPEND_SLASH 行為之外

    from django.views.decorators.common import no_append_slash
    
    
    @no_append_slash
    def sensitive_fbv(request, *args, **kwargs):
        """View to be excluded from APPEND_SLASH."""
        return HttpResponse()
    
  • 為非串流回應設定 Content-Length 標頭。

class BrokenLinkEmailsMiddleware[原始碼]

GZip 中介層

class GZipMiddleware[原始碼]
max_random_bytes

預設為 100。繼承 GZipMiddleware 並覆寫此屬性,以變更壓縮回應中包含的最大隨機位元組數。

注意

安全研究人員指出,當網站上使用壓縮技術(包括 GZipMiddleware)時,該網站可能會暴露於許多可能的攻擊中。

為了減輕攻擊,Django 實作了一種稱為Heal The Breach (HTB) 的技術。它會將最多 100 個位元組(請參閱 max_random_bytes)的隨機位元組新增至每個回應,以降低攻擊的有效性。

如需更多詳細資訊,請參閱BREACH 論文 (PDF)breachattack.comHeal The Breach (HTB) 論文

django.middleware.gzip.GZipMiddleware 會為了解 GZip 壓縮的瀏覽器壓縮內容(所有現代瀏覽器)。

此中介層應放置在任何其他需要讀取或寫入回應主體的中介層之前,以便稍後進行壓縮。

如果符合下列任何條件,則它不會壓縮內容

  • 內容主體長度少於 200 個位元組。

  • 回應已設定 Content-Encoding 標頭。

  • 請求(瀏覽器)尚未傳送包含 gzipAccept-Encoding 標頭。

如果回應具有 ETag 標頭,則 ETag 會變得較弱,以符合 RFC 9110 第 8.8.1 節

您可以使用 gzip_page() 修飾器將 GZip 壓縮套用至個別視圖。

條件式 GET 中介層

class ConditionalGetMiddleware[原始碼]

處理條件式 GET 作業。如果回應沒有 ETag 標頭,則中介層會在需要時新增一個。如果回應具有 ETagLast-Modified 標頭,且請求具有 If-None-MatchIf-Modified-Since,則回應會取代為 HttpResponseNotModified

地區設定中介層

class LocaleMiddleware[原始碼]
response_redirect_class

預設為 HttpResponseRedirect。繼承 LocaleMiddleware 並覆寫此屬性,以自訂中介軟體發出的重新導向。

啟用基於請求資料的語言選擇。它為每個使用者自訂內容。請參閱國際化文件

訊息中介軟體

class MessageMiddleware[原始碼]

啟用基於 Cookie 和 Session 的訊息支援。請參閱訊息文件

安全性中介軟體

警告

如果您的部署情況允許,通常最好讓您的前端 Web 伺服器執行 SecurityMiddleware 提供的功能。這樣,如果有一些請求不是由 Django 處理(例如靜態媒體或使用者上傳的檔案),它們將與對 Django 應用程式的請求具有相同的保護。

class SecurityMiddleware[原始碼]

django.middleware.security.SecurityMiddleware 為請求/回應週期提供多項安全性增強功能。每個功能都可以使用設定獨立啟用或停用。

HTTP 嚴格傳輸安全

對於僅應透過 HTTPS 存取的網站,您可以透過設定 “Strict-Transport-Security” 標頭,指示現代瀏覽器拒絕透過不安全的連線連線到您的網域名稱(在給定的時間段內)。這可以減少您遭受某些 SSL 剝離中間人(MITM)攻擊的風險。

如果您將 SECURE_HSTS_SECONDS 設定為非零整數值,SecurityMiddleware 會在所有 HTTPS 回應中為您設定此標頭。

在啟用 HSTS 時,最好先使用較小的值進行測試,例如,SECURE_HSTS_SECONDS = 3600 表示一小時。每次 Web 瀏覽器看到您網站的 HSTS 標頭時,它都會拒絕在給定的時間段內與您的網域進行不安全的通訊(使用 HTTP)。一旦您確認所有資產都在您的網站上安全提供(即 HSTS 沒有破壞任何東西),最好增加此值,以便保護不常來訪的使用者(31536000 秒,即 1 年,是常見的)。

此外,如果您將 SECURE_HSTS_INCLUDE_SUBDOMAINS 設定為 TrueSecurityMiddleware 將在 Strict-Transport-Security 標頭中新增 includeSubDomains 指令。建議這樣做(假設所有子網域都僅使用 HTTPS 提供),否則您的網站可能仍然會透過不安全的連線連線到子網域而受到攻擊。

如果您希望將您的網站提交到 瀏覽器預先載入清單,請將 SECURE_HSTS_PRELOAD 設定為 True。這會將 preload 指令附加到 Strict-Transport-Security 標頭。

警告

HSTS 政策適用於您的整個網域,而不僅僅是您在其上設定標頭的回應 URL。因此,只有在您的整個網域僅透過 HTTPS 提供時,才應使用它。

正確遵守 HSTS 標頭的瀏覽器將拒絕允許使用者繞過警告,並連線到具有過期、自簽名或以其他方式無效的 SSL 憑證的網站。如果您使用 HSTS,請確保您的憑證狀態良好並保持良好狀態!

注意

如果您部署在負載平衡器或反向 Proxy 伺服器後面,並且沒有將 Strict-Transport-Security 標頭新增至您的回應,則可能是因為 Django 沒有意識到它正在進行安全的連線;您可能需要設定 SECURE_PROXY_SSL_HEADER 設定。

Referrer 政策

瀏覽器使用 Referer 標頭作為向網站傳送使用者如何到達那裡之資訊的方式。當使用者點擊連結時,瀏覽器將傳送連結頁面的完整 URL 作為參照位址。雖然這對於某些目的可能很有用 – 例如弄清楚誰連結到您的網站 – 但它也可能會引起隱私問題,因為它會通知一個網站使用者正在訪問另一個網站。

某些瀏覽器能夠接受關於它們是否應該在使用者點擊連結時傳送 HTTP Referer 標頭的提示;此提示是透過 Referrer-Policy 標頭提供的。此標頭可以向瀏覽器建議三種行為

  • 完整 URL:在 Referer 標頭中傳送整個 URL。例如,如果使用者正在訪問 https://example.com/page.html,則 Referer 標頭將包含 "https://example.com/page.html"

  • 僅限來源:僅在參照位址中傳送「來源」。來源包括方案、主機和(可選)連接埠號碼。例如,如果使用者正在訪問 https://example.com/page.html,則來源將為 https://example.com/

  • 無參照位址:完全不傳送 Referer 標頭。

此標頭可以告知瀏覽器注意兩種條件

  • 相同來源與跨來源:從 https://example.com/1.htmlhttps://example.com/2.html 的連結是相同來源。從 https://example.com/page.htmlhttps://not.example.com/page.html 的連結是跨來源。

  • 協定降級:如果包含連結的頁面是透過 HTTPS 提供,但連結到的頁面不是透過 HTTPS 提供,則會發生降級。

警告

當您的網站透過 HTTPS 提供時,Django 的 CSRF 保護系統 需要存在 Referer 標頭,因此完全停用 Referer 標頭會干擾 CSRF 保護。為了在保持 CSRF 保護的同時獲得停用 Referer 標頭的大部分好處,請考慮僅啟用相同來源的參照位址。

SecurityMiddleware 可以根據 SECURE_REFERRER_POLICY 設定為您設定 Referrer-Policy 標頭(請注意拼寫:當使用者點擊連結時,瀏覽器會傳送 Referer 標頭,但指示瀏覽器是否這樣做的標頭拼寫為 Referrer-Policy)。此設定的有效值為

no-referrer

指示瀏覽器不為在此網站上點擊的連結傳送參照位址。

no-referrer-when-downgrade

指示瀏覽器傳送完整的 URL 作為參照位址,但僅當沒有發生協定降級時。

origin

指示瀏覽器僅傳送來源,而不是完整 URL,作為參照位址。

origin-when-cross-origin

指示瀏覽器為相同來源連結傳送完整的 URL 作為參照位址,而僅為跨來源連結傳送來源。

same-origin

指示瀏覽器傳送完整 URL,但僅針對相同來源連結。不會傳送跨來源連結的參照位址。

strict-origin

指示瀏覽器僅傳送來源,而不是完整 URL,並且在發生協定降級時不傳送參照位址。

strict-origin-when-cross-origin

指示瀏覽器在連結為相同來源且未發生協定降級時傳送完整 URL;當連結為跨來源且未發生協定降級時,僅傳送來源;並且在發生協定降級時不傳送參照位址。

unsafe-url

指示瀏覽器始終傳送完整 URL 作為參照位址。

未知的政策值

如果使用者代理程式未知政策值,則可以指定多個政策值來提供後備。最後一個理解的值優先。為了支援此功能,可將可迭代或逗號分隔的字串與 SECURE_REFERRER_POLICY 一起使用。

跨來源開啟器政策

某些瀏覽器具有將頂層視窗與其他文件隔離的能力,方法是根據 跨來源開啟器策略 (Cross-Origin Opener Policy,COOP) 標頭的值,將它們放入一個獨立的瀏覽內容群組中。如果以這種方式隔離的文件開啟一個跨來源彈出視窗,該彈出視窗的 window.opener 屬性將會是 null。使用 COOP 隔離視窗是對抗跨來源攻擊的深度防禦機制,尤其是像 Spectre 這樣的攻擊,它允許洩露載入到共享瀏覽內容中的資料。

SecurityMiddleware 可以根據 SECURE_CROSS_ORIGIN_OPENER_POLICY 設定,為您設定 Cross-Origin-Opener-Policy 標頭。此設定的有效值為:

same-origin

將瀏覽內容僅限於同源文件。跨來源文件不會載入到相同的瀏覽內容中。這是預設且最安全的選項。

same-origin-allow-popups

將瀏覽內容隔離到同源文件,或那些未設定 COOP 或選擇透過設定 unsafe-none 的 COOP 來退出隔離的文件。

unsafe-none

允許將文件新增到其開啟器的瀏覽內容群組中,除非開啟器本身具有 same-originsame-origin-allow-popups 的 COOP。

X-Content-Type-Options: nosniff

某些瀏覽器會嘗試猜測它們擷取資源的內容類型,覆寫 Content-Type 標頭。雖然這有助於顯示配置不當的伺服器上的網站,但也可能構成安全風險。

如果您的網站提供使用者上傳的檔案,惡意使用者可能會上傳一個經過特殊設計的檔案,當您預期它是無害的東西時,瀏覽器會將其解釋為 HTML 或 JavaScript。

為了防止瀏覽器猜測內容類型並強制其始終使用 Content-Type 標頭中提供的類型,您可以傳遞 X-Content-Type-Options: nosniff 標頭。如果 SECURE_CONTENT_TYPE_NOSNIFF 設定為 TrueSecurityMiddleware 會對所有回應執行此操作。

請注意,在大多數 Django 不參與提供使用者上傳檔案的部署情況下,此設定不會對您有所幫助。例如,如果您的 MEDIA_URL 是由您的前端網頁伺服器 (nginx、Apache 等) 直接提供的,那麼您需要在該處設定此標頭。另一方面,如果您使用 Django 執行類似要求授權才能下載檔案之類的操作,並且無法使用網頁伺服器設定標頭,則此設定會很有用。

SSL 重新導向

如果您的網站同時提供 HTTP 和 HTTPS 連線,大多數使用者預設會使用不安全的連線。為了獲得最佳安全性,您應該將所有 HTTP 連線重新導向至 HTTPS。

如果您將 SECURE_SSL_REDIRECT 設定設為 True,SecurityMiddleware 會永久 (HTTP 301) 將所有 HTTP 連線重新導向至 HTTPS。

注意

基於效能考量,最好在 Django 之外、在前端負載平衡器或反向代理伺服器 (例如 nginx) 中執行這些重新導向。SECURE_SSL_REDIRECT 適用於無法選擇這種方式的部署情況。

如果 SECURE_SSL_HOST 設定有一個值,所有重新導向都會傳送到該主機,而不是原始請求的主機。

如果您的網站上有少數頁面應該透過 HTTP 提供,而不應該重新導向至 HTTPS,您可以在 SECURE_REDIRECT_EXEMPT 設定中列出與這些 URL 相符的正規表示式。

注意

如果您部署在負載平衡器或反向代理伺服器後方,且 Django 看來無法判斷請求是否已安全,您可能需要設定 SECURE_PROXY_SSL_HEADER 設定。

工作階段中介軟體

class SessionMiddleware[來源]

啟用工作階段支援。請參閱工作階段文件

網站中介軟體

class CurrentSiteMiddleware[來源]

將代表目前網站的 site 屬性新增至每個傳入的 HttpRequest 物件。請參閱網站文件

驗證中介軟體

class AuthenticationMiddleware[來源]

將代表目前已登入使用者的 user 屬性新增至每個傳入的 HttpRequest 物件。請參閱網頁請求中的驗證

class LoginRequiredMiddleware[來源]

對中介軟體進行子類別化,並覆寫下列屬性和方法,以自訂未驗證請求的行為。

redirect_field_name

預設為 "next"

get_login_url()[來源]

傳回未驗證請求將重新導向到的 URL。此結果是 login_required()裝飾器上設定的 login_url (如果不是 None),或是 settings.LOGIN_URL

get_redirect_field_name()[來源]

傳回包含使用者在成功登入後應重新導向至的 URL 的查詢參數名稱。此結果是 login_required() 裝飾器上設定的 redirect_field_name (如果不是 None),或是 redirect_field_name。如果傳回 None,則不會新增查詢參數。

Django 5.1 中的新增功能。

將所有未驗證的請求重新導向至登入頁面,但使用 login_not_required() 排除的檢視除外。登入頁面預設為 settings.LOGIN_URL,但可以自訂。

透過將此中介軟體新增至 MIDDLEWARE 設定中,在 AuthenticationMiddleware 之後啟用此中介軟體

MIDDLEWARE = [
    "...",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.auth.middleware.LoginRequiredMiddleware",
    "...",
]

使用 login_not_required() 將檢視設定為公開,允許未驗證的請求。例如:

from django.contrib.auth.decorators import login_not_required


@login_not_required
def contact_us(request): ...

使用 login_required() 裝飾器,分別設定 login_urlredirect_field_name,自訂已驗證檢視的登入 URL 或欄位名稱。例如:

from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import View


@login_required(login_url="/books/login/", redirect_field_name="redirect_to")
def book_dashboard(request): ...


@method_decorator(
    login_required(login_url="/books/login/", redirect_field_name="redirect_to"),
    name="dispatch",
)
class BookMetrics(View):
    pass
class RemoteUserMiddleware[來源]

用於利用網頁伺服器提供的驗證的中介軟體。有關使用詳細資訊,請參閱如何使用 REMOTE_USER 驗證

class PersistentRemoteUserMiddleware[來源]

中介軟體,用於在僅於登入頁面啟用時,利用網路伺服器提供的身份驗證。有關使用細節,請參閱 僅在登入頁面使用 REMOTE_USER

CSRF 保護中介軟體

class CsrfViewMiddleware[原始碼]

透過在 POST 表單中新增隱藏欄位並檢查請求是否具有正確的值,來增加對跨站請求偽造的保護。請參閱 跨站請求偽造保護文件

X-Frame-Options 中介軟體

class XFrameOptionsMiddleware[原始碼]

透過 X-Frame-Options 標頭提供的簡單點擊劫持保護

中介軟體排序

以下是一些關於各種 Django 中介軟體類別的排序提示

  1. SecurityMiddleware

    如果您要開啟 SSL 重新導向,它應該盡可能靠近清單頂端,這樣可以避免執行一堆其他不必要的中介軟體。

  2. UpdateCacheMiddleware

    在修改 Vary 標頭的那些中介軟體之前 (SessionMiddlewareGZipMiddlewareLocaleMiddleware)。

  3. GZipMiddleware

    在任何可能會更改或使用回應主體的中介軟體之前。

    UpdateCacheMiddleware 之後:修改 Vary 標頭。

  4. SessionMiddleware

    在任何可能會引發異常以觸發錯誤檢視的中介軟體之前 (例如 PermissionDenied),如果您正在使用 CSRF_USE_SESSIONS

    UpdateCacheMiddleware 之後:修改 Vary 標頭。

  5. ConditionalGetMiddleware

    在任何可能會更改回應的中介軟體之前 (它會設定 ETag 標頭)。

    GZipMiddleware 之後,這樣它就不會對 gzipped 內容計算 ETag 標頭。

  6. LocaleMiddleware

    最頂層的中介軟體之一,在 SessionMiddleware (使用 session 資料) 和 UpdateCacheMiddleware (修改 Vary 標頭) 之後。

  7. CommonMiddleware

    在任何可能會更改回應的中介軟體之前 (它會設定 Content-Length 標頭)。出現在 CommonMiddleware 之前並更改回應的中介軟體必須重設 Content-Length

    靠近頂端:當 APPEND_SLASHPREPEND_WWW 設定為 True 時,它會重新導向。

    如果您正在使用 CSRF_USE_SESSIONS,則在 SessionMiddleware 之後。

  8. CsrfViewMiddleware

    在任何假定已處理 CSRF 攻擊的檢視中介軟體之前。

    RemoteUserMiddleware 或任何其他可能會在呼叫中介軟體鏈之前執行登入,因此會輪換 CSRF 權杖的身份驗證中介軟體之前。

    如果您正在使用 CSRF_USE_SESSIONS,則在 SessionMiddleware 之後。

  9. AuthenticationMiddleware

    SessionMiddleware 之後:使用 session 儲存。

  10. LoginRequiredMiddleware

    Django 5.1 中的新增功能。

    AuthenticationMiddleware 之後:使用 user 物件。

  11. MessageMiddleware

    SessionMiddleware 之後:可以使用基於 session 的儲存。

  12. FetchFromCacheMiddleware

    在任何修改 Vary 標頭的中介軟體之後:該標頭用於為快取雜湊鍵選擇一個值。

  13. FlatpageFallbackMiddleware

    應該盡可能靠近底部,因為它是一種最後手段的中介軟體。

  14. RedirectFallbackMiddleware

    應該盡可能靠近底部,因為它是一種最後手段的中介軟體。

回到頂端