Django 的安全性

本文概述了 Django 的安全性功能。它包含了關於保護由 Django 驅動的網站安全的建議。

跨站腳本 (XSS) 保護

XSS 攻擊允許使用者將用戶端腳本注入到其他使用者的瀏覽器中。這通常是透過將惡意腳本儲存在資料庫中來實現,這些腳本將被檢索並顯示給其他使用者,或者透過讓使用者點擊連結,導致攻擊者的 JavaScript 在使用者的瀏覽器中執行。然而,每當資料在包含在頁面中之前未經過充分清理時,XSS 攻擊可能源自任何不受信任的資料來源,例如 Cookie 或網路服務。

使用 Django 模板可以保護您免受大多數 XSS 攻擊。但是,了解它提供的保護及其局限性非常重要。

Django 模板會 跳脫特定字元,這些字元對 HTML 特別危險。雖然這可以保護使用者免受大多數惡意輸入的侵害,但它並非完全萬無一失。例如,它不會保護以下情況:

<style class={{ var }}>...</style>

如果 var 設定為 'class1 onmouseover=javascript:func()',這可能會導致未經授權的 JavaScript 執行,具體取決於瀏覽器如何呈現不完美的 HTML。(為屬性值加上引號可以解決這種情況。)

當搭配自訂模板標籤、safe 模板標籤、mark_safe 使用 is_safe 時,以及當自動跳脫關閉時,也必須特別小心。

此外,如果您使用模板系統來輸出 HTML 以外的內容,可能會有完全不同的字元和單字需要跳脫。

當將 HTML 儲存在資料庫中時,也應非常小心,特別是當該 HTML 被檢索並顯示時。

跨站請求偽造 (CSRF) 保護

CSRF 攻擊允許惡意使用者在另一個使用者不知情或不同意的情況下,使用該使用者的憑證執行操作。

Django 內建了針對大多數類型的 CSRF 攻擊的保護,前提是您在適當的地方啟用並使用它。然而,與任何緩解技術一樣,都有其局限性。例如,可以全域或針對特定視圖停用 CSRF 模組。只有在您知道自己在做什麼的情況下才應該這樣做。如果您的網站有不在您控制範圍內的子網域,則存在其他限制

CSRF 保護運作方式 是檢查每個 POST 請求中的機密。這可確保惡意使用者無法「重播」對您網站的表單 POST,並讓其他登入的使用者不知情地提交該表單。惡意使用者必須知道這個機密,這是使用者特定的(使用 Cookie)。

當使用 HTTPS 部署時,CsrfViewMiddleware 將檢查 HTTP 參照標頭是否設定為相同來源(包括子網域和連接埠)上的 URL。由於 HTTPS 提供額外的安全性,因此必須確保連線使用 HTTPS(如果可用),方法是轉發不安全的連線請求並對支援的瀏覽器使用 HSTS。

除非絕對必要,否則請非常小心地使用 csrf_exempt 修飾器標記視圖。

SQL 注入保護

SQL 注入是一種攻擊,惡意使用者能夠在資料庫上執行任意 SQL 程式碼。這可能導致記錄被刪除或資料外洩。

Django 的查詢集受到 SQL 注入的保護,因為它們的查詢是使用查詢參數化來建構的。查詢的 SQL 程式碼與查詢的參數分開定義。由於參數可能是使用者提供的,因此不安全,它們會由基礎資料庫驅動程式跳脫。

Django 也賦予開發人員編寫原始查詢或執行自訂 SQL的能力。應謹慎使用這些功能,並且應始終小心地正確跳脫使用者可以控制的任何參數。此外,當使用 extra()RawSQL 時,應謹慎行事。

點擊劫持保護

點擊劫持是一種攻擊,惡意網站將另一個網站包裝在框架中。這種攻擊可能會導致毫無戒心的使用者被誘騙在目標網站上執行不希望的操作。

Django 包含以 點擊劫持保護 的形式,即 X-Frame-Options 中介軟體,在支援的瀏覽器中,它可以防止網站在框架內呈現。可以針對每個視圖停用保護,或設定要傳送的確切標頭值。

強烈建議任何不需要由第三方網站將其頁面包裝在框架中的網站,或只需要允許網站的一小部分這樣做的網站使用此中介軟體。

SSL/HTTPS

為了安全起見,始終最好在 HTTPS 後面部署您的網站。如果沒有 HTTPS,惡意的網路使用者可能會嗅探驗證憑證或用戶端和伺服器之間傳輸的任何其他資訊,並且在某些情況下, 活動的 網路攻擊者可能會更改任一方向傳送的資料。

如果您想要 HTTPS 提供的保護,並且已在伺服器上啟用它,則可能需要執行一些額外的步驟:

  • 如有必要,請設定 SECURE_PROXY_SSL_HEADER,確保您已徹底了解其中的警告。否則可能會導致 CSRF 漏洞,並且錯誤地執行操作也可能很危險!

  • SECURE_SSL_REDIRECT 設定為 True,以便透過 HTTP 發出的請求重新導向到 HTTPS。

    請注意 SECURE_PROXY_SSL_HEADER 下的注意事項。對於反向 Proxy 的情況,設定主網路伺服器重新導向到 HTTPS 可能更容易或更安全。

  • 使用「安全」Cookie。

    如果瀏覽器最初透過 HTTP 連線(這是大多數瀏覽器的預設值),則可能會洩漏現有的 Cookie。因此,您應該將 SESSION_COOKIE_SECURECSRF_COOKIE_SECURE 設定設定為 True。這會指示瀏覽器僅透過 HTTPS 連線傳送這些 Cookie。請注意,這表示工作階段無法透過 HTTP 工作,並且 CSRF 保護將阻止透過 HTTP 接受任何 POST 資料(如果您將所有 HTTP 流量重新導向到 HTTPS,這將沒問題)。

  • 使用 HTTP 嚴格傳輸安全性 (HSTS)

    HSTS 是一個 HTTP 標頭,它會通知瀏覽器,未來與特定網站的所有連線都應該始終使用 HTTPS。結合將 HTTP 請求重新導向至 HTTPS,這將確保連線始終享有 SSL 提供的額外安全性,前提是已成功建立一次連線。HSTS 可以透過 SECURE_HSTS_SECONDSSECURE_HSTS_INCLUDE_SUBDOMAINSSECURE_HSTS_PRELOAD 設定,或在網頁伺服器上進行設定。

主機標頭驗證

Django 會使用用戶端提供的 Host 標頭,在某些情況下建構 URL。雖然這些值會經過清理以防止跨網站指令碼攻擊,但偽造的 Host 值可用於跨網站請求偽造、快取中毒攻擊和電子郵件中毒連結。

由於即使是看似安全的網頁伺服器設定也容易受到偽造的 Host 標頭攻擊,Django 會根據 ALLOWED_HOSTS 設定,在 django.http.HttpRequest.get_host() 方法中驗證 Host 標頭。

此驗證僅透過 get_host() 應用;如果您的程式碼直接從 request.META 存取 Host 標頭,則您正在繞過此安全保護。

有關更多詳細資訊,請參閱完整的 ALLOWED_HOSTS 文件。

警告

此文件之前的版本建議您設定網頁伺服器,以確保它會驗證傳入的 HTTP Host 標頭。雖然仍然建議這樣做,但在許多常見的網頁伺服器中,看似會驗證 Host 標頭的設定實際上可能並非如此。例如,即使 Apache 設定為從具有設定 ServerName 的非預設虛擬主機提供您的 Django 網站,HTTP 請求仍然有可能比對此虛擬主機並提供偽造的 Host 標頭。因此,Django 現在要求您明確設定 ALLOWED_HOSTS,而不是依賴網頁伺服器設定。

此外,如果您的設定需要,Django 也會要求您明確啟用對 X-Forwarded-Host 標頭的支援(透過 USE_X_FORWARDED_HOST 設定)。

引薦來源政策

瀏覽器使用 Referer 標頭來向網站發送有關使用者如何到達該處的資訊。透過設定引薦來源政策,您可以幫助保護使用者的隱私,限制在哪些情況下會設定 Referer 標頭。有關詳細資訊,請參閱安全中間體參考的引薦來源政策部分

跨來源開啟器政策

跨來源開啟器政策 (COOP) 標頭允許瀏覽器將頂層視窗與其他文件隔離,方法是將它們放入不同的內容群組,使它們無法直接與頂層視窗互動。如果受 COOP 保護的文件開啟跨來源彈出視窗,則彈出視窗的 window.opener 屬性將為 null。COOP 可防止跨來源攻擊。有關詳細資訊,請參閱安全中間體參考的跨來源開啟器政策部分

工作階段安全性

CSRF 限制類似,要求網站的部署方式應使不受信任的使用者無法存取任何子網域,django.contrib.sessions 也有限制。有關詳細資訊,請參閱有關安全性的工作階段主題指南部分

使用者上傳的內容

注意

考慮從雲端服務或 CDN 提供靜態檔案,以避免其中一些問題。

  • 如果您的網站接受檔案上傳,強烈建議您在網頁伺服器設定中將這些上傳限制為合理的大小,以防止阻斷服務 (DOS) 攻擊。在 Apache 中,可以使用 LimitRequestBody 指令輕鬆設定此值。

  • 如果您正在提供自己的靜態檔案,請確保停用諸如 Apache 的 mod_php 等會將靜態檔案作為程式碼執行的處理常式。您不希望使用者能夠透過上傳和請求特製的檔案來執行任意程式碼。

  • 當以不遵循安全性最佳做法的方式提供媒體時,Django 的媒體上傳處理會造成一些漏洞。具體來說,如果 HTML 檔案包含有效的 PNG 標頭,後接惡意的 HTML,則該檔案可以作為映像上傳。此檔案將通過 Django 用於 ImageField 映像處理(Pillow)的程式庫驗證。當隨後向使用者顯示此檔案時,根據網頁伺服器的類型和設定,可能會顯示為 HTML。

    在框架層級上,沒有萬無一失的技術解決方案可以安全地驗證所有使用者上傳的檔案內容,但是,您可以採取其他一些步驟來減輕這些攻擊

    1. 一類攻擊可以透過始終從不同的頂層或第二層網域提供使用者上傳的內容來防止。這可以防止任何被同源政策保護(例如跨網站指令碼)封鎖的漏洞。例如,如果您的網站在 example.com 上執行,您會希望從類似 usercontent-example.com 的位置提供上傳的內容(MEDIA_URL 設定)。從類似 usercontent.example.com 的子網域提供內容是不夠的。

    2. 除此之外,應用程式可以選擇定義使用者上傳檔案的可允許檔案副檔名清單,並設定網頁伺服器僅提供此類檔案。

其他安全性主題

雖然 Django 提供了良好的現成安全性保護,但正確部署您的應用程式並利用網頁伺服器、作業系統和其他元件的安全性保護仍然非常重要。

  • 請確保您的 Python 程式碼位於網頁伺服器的根目錄之外。這將確保您的 Python 程式碼不會意外地以純文字形式提供(或意外地執行)。

  • 請謹慎處理任何使用者上傳的檔案

  • Django 不會限制對驗證使用者的請求。為了防止針對驗證系統的暴力攻擊,您可以考慮部署 Django 外掛程式或網頁伺服器模組來限制這些請求。

  • 請確保您的 SECRET_KEYSECRET_KEY_FALLBACKS(如果使用)是機密的。

  • 最好使用防火牆限制您的快取系統和資料庫的存取權。

  • 請查看開放網路應用程式安全專案 (OWASP) 前 10 名清單,該清單指出網頁應用程式中的一些常見漏洞。雖然 Django 有工具可以解決某些問題,但其他問題必須在您的專案設計中加以考慮。

  • Mozilla 討論了有關網頁安全性的各種主題。他們的頁面還包括適用於任何系統的安全性原則。

返回頂部