在 Django 開發中,設定 HTTPS 並強化 Cookie 安全性是不可或缺的環節。本文將逐步說明如何使用 Gunicorn 佈署 HTTPS,設定相關安全性引數,並探討資料函式庫和郵件加密,最後深入講解 Cookie 的安全設定,包含 Secure 和 Domain 指令,以提升網站整體安全性,保護使用者資料。透過整合這些技術,可以有效防止中間人攻擊等資安威脅,確保網站資料傳輸的機密性與完整性。

設定 Django 專案

現在,您需要設定您的 Django 專案。您可以使用 manage.py 指令碼來啟動您的 Django 應用程式:

$ python manage.py runserver

這個命令將啟動您的 Django 應用程式,並在 http://localhost:8000/ 上提供服務。

使用 HTTPS 加密您的 Django 應用程式

為了加密您的 Django 應用程式,您需要使用 HTTPS。您可以使用 Let’s Encrypt 取得免費的 SSL/TLS 證書。Let’s Encrypt 是一個非營利組織,提供免費的 SSL/TLS 證書,以幫助您加密您的 Web 應用程式。

內容解密:
  • Django 是一個 Python Web 應用程式框架,提供了許多功能和工具來幫助您建立安全和可擴充套件的 Web 應用程式。
  • manage.py 指令碼是一個專案特定的管理工具,將幫助您啟動您的 Django 應用程式。
  • Django 根目錄包含了許多重要的模組,包括 settings 模組。
  • Let’s Encrypt 是一個非營利組織,提供免費的 SSL/TLS 證書,以幫助您加密您的 Web 應用程式。

圖表翻譯:

  graph LR
    A[Django] -->|使用|> B[manage.py]
    B -->|啟動|> C[Django 應用程式]
    C -->|使用 HTTPS|> D[Let's Encrypt]
    D -->|加密|> E[Django 應用程式]

這個圖表展示瞭如何使用 Django 建立、設定和執行一個 Web 應用程式伺服器,並如何使用 HTTPS 加密您的 Django 應用程式。

使用Django和Gunicorn實作HTTPS

要使用Django和Gunicorn實作HTTPS,需要先了解Django的專案結構和設定。Django專案的結構通常如下所示:

project/
    manage.py
    project/
        __init__.py
        settings.py
        urls.py
        wsgi.py

在這個結構中,settings.py檔案包含了Django專案的設定,包括除錯模式(DEBUG)的設定。

除錯模式(DEBUG)

Django的除錯模式(DEBUG)是一個重要的設定引數。當DEBUG設為True時,Django會顯示詳細的錯誤頁面,包括專案目錄結構、設定引數和程式狀態。

# settings.py
DEBUG = True

但是,需要注意的是,DEBUG設為True不適合生產環境,因為它會顯示敏感的錯誤資訊。

使用Gunicorn

Gunicorn是一個純Python的WSGI協定實作,用於解耦Web應用框架和Web伺服器實作。要使用Gunicorn,需要先安裝它:

$ pipenv install gunicorn

然後,需要停止正在執行的Django應用程式,然後使用Gunicorn啟動Django伺服器:

$ gunicorn project.wsgi

這會啟動Gunicorn伺服器,然後可以透過http://localhost:8000存取Django應用程式。

HTTPS

要升級到HTTPS,需要安裝一個公鑰證書。可以使用自簽名的公鑰證書,這是一個便宜且方便的解決方案。

$ openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout key.pem -days 365

這會生成一個自簽名的公鑰證書和私鑰。

然後,需要組態Gunicorn使用這個證書:

$ gunicorn --certfile cert.pem --keyfile key.pem project.wsgi

這會啟動Gunicorn伺服器,使用HTTPS協定。

內容解密:
  • Django的專案結構和設定是實作HTTPS的基礎。
  • Gunicorn是一個純Python的WSGI協定實作,用於解耦Web應用框架和Web伺服器實作。
  • 自簽名的公鑰證書是一個便宜且方便的解決方案,但不適合生產環境。

圖表翻譯:

  graph LR
    A[Django] --> B[Gunicorn]
    B --> C[HTTPS]
    C --> D[公鑰證書]
    D --> E[自簽名證書]

這個圖表顯示了Django、Gunicorn、HTTPS和公鑰證書之間的關係。

HTTPS 協定升級與自簽憑證

為了提升網站的安全性,從 HTTP 協定升級到 HTTPS 是一個重要的步驟。HTTPS 可以確保資料在傳輸過程中的保密性和完整性。以下是升級的步驟和使用自簽憑證的過程。

生成自簽憑證

首先,需要生成一個自簽的公鑰憑證。這可以使用 OpenSSL 進行。以下命令生成了一個有效期為 10 年的自簽憑證和一個橢圓曲線金鑰對:

$ openssl req -x509 \
  -nodes -days 3650 \
  -newkey ec:<(openssl ecparam -name prime256v1) \
  -keyout private_key.pem \
  -out certificate.pem

這個命令會提示輸入憑證的主體詳細資訊,包括國家、州或省、城市、組織名稱、組織單位名稱和共同名稱(例如,完全限定主機名稱)。為了進行本地開發,共同名稱應該設定為 localhost

安裝憑證

生成憑證後,需要安裝它。這涉及到重啟 Gunicorn 服務,並指定私鑰檔案和憑證檔案的路徑:

$ gunicorn alice.wsgi \
  --keyfile private_key.pem \
  --certfile certificate.pem

這樣,Gunicorn 就會使用安裝的憑證來提供 HTTPS 服務。

信任自簽憑證

由於自簽憑證不能被瀏覽器自動信任,需要手動將其新增到作業系統的信任憑證儲存中。以下是 macOS 上的步驟:

  1. 開啟 Keychain Access。
  2. 將自簽憑證拖入 Keychain Access 的憑證部分。
  3. 在 Keychain Access 中雙擊憑證。
  4. 展開信任部分。
  5. 在 “當使用此憑證” 下拉列表中,選擇 “始終信任”。

對於其他作業系統,需要查詢特定的指導以新增自簽憑證到信任儲存中。

HTTPS 協定升級的好處

升級到 HTTPS 協定可以大大提高網站的安全性。以下是兩個額外的步驟,可以使伺服器更加安全:

  1. 禁止 HTTP 請求,使用 Strict-Transport-Security 回應頭。
  2. 導向入站 HTTP 請求到 HTTPS。

這些步驟可以確保所有的通訊都是透過安全的 HTTPS 協定進行的,從而保護使用者的資料和防止中間人攻擊。

6.5.2 嚴格運輸安全性(HSTS)回應標頭

當伺服器想要告知瀏覽器應該僅透過HTTPS存取時,會使用HTTP嚴格運輸安全性(HSTS)回應標頭。例如,伺服器可以使用以下回應標頭,指示瀏覽器在接下來的3600秒(1小時)內僅透過HTTPS存取:

Strict-Transport-Security: max-age=3600

冒號右側的鍵值對稱為指令,指令用於引數化HTTP標頭。在此情況下,max-age指令代表瀏覽器應該僅透過HTTPS存取網站的時間(以秒為單位)。

確保您的Django應用程式的每個回應都包含HSTS標頭,方法是設定SECURE_HSTS_SECONDS引數。這個引數的值對應於標頭的max-age指令,任何正整數都是有效的值。

警告:如果您正在處理一個已經在生產環境中的系統,請小心使用SECURE_HSTS_SECONDS。這個設定適用於整個網站,而不是僅僅是請求的資源。如果您的更改破壞了任何東西,影響可能會持續到max-age指令的值。為了安全起見,從一個小的值開始增加SECURE_HSTS_SECONDS是一個更安全的方式。您可以問自己,如果出了問題,您能夠忍受多長時間的停機時間。

伺服器可以傳送HSTS回應標頭,包含includeSubDomains指令,指示瀏覽器所有子網域也應該僅透過HTTPS存取。例如:

Strict-Transport-Security: max-age=3600; includeSubDomains

SECURE_HSTS_INCLUDE_SUBDOMAINS設定用於組態Django傳送HSTS回應標頭,包含includeSubDomains指令。這個設定預設為False,如果SECURE_HSTS_SECONDS不是正整數,則會被忽略。

警告:與SECURE_HSTS_SECONDS相關的所有風險也適用於SECURE_HSTS_INCLUDE_SUBDOMAINS。如果您正在處理一個已經在生產環境中的系統,從一個小的值開始增加SECURE_HSTS_INCLUDE_SUBDOMAINS是一個更安全的方式。

6.5.3 HTTPS重定向

HSTS標頭是一個良好的防禦層,但作為一個回應標頭,它只能做到一定的程度;瀏覽器必須先傳送請求,然後才能收到HSTS標頭。因此,當初始請求是透過HTTP傳送時,重定向瀏覽器到HTTPS是有用的。

確保您的Django應用程式重定向HTTP請求到HTTPS,方法是設定SECURE_SSL_REDIRECT引數為True。這個設定預設為False,您應該將其設為True,如果您的網站使用HTTPS。

SECURE_REDIRECT_EXEMPT設定是一個正規表示式列表,指定哪些URL不需要重定向到HTTPS。這個設定在下一節中會被涵蓋。

使用Python的requests套件進行HTTPS請求

當我們使用Python的requests套件進行HTTPS請求時,套件會自動使用TLS進行加密。然而,我們可以使用verify關鍵字引數來停用伺服器驗證。這並不會停用TLS加密,但會放寬TLS驗證,讓伺服器不需要驗證。

import requests

url = "https://example.com"
response = requests.get(url, verify=False)
print(response)

這種方法通常不適合用於生產環境,但在整合測試環境中可能很有用,例如當系統需要與沒有靜態主機名稱的伺服器或使用自簽憑證的伺服器進行通訊時。

客戶端驗證

TLS驗證是雙向的:客戶端也可以像伺服器一樣進行驗證。客戶端使用公鑰憑證和私鑰進行驗證,就像伺服器一樣。requests套件支援客戶端驗證,使用cert關鍵字引數。這個引數需要一個包含憑證和私鑰檔案路徑的元組。

import requests

url = "https://example.com"
cert = ('/path/to/certificate.pem', '/path/to/private_key.pem')
response = requests.get(url, cert=cert)
print(response)

使用requests.Session物件

requests套件也提供了一個Session物件,讓我們可以設定verifycert引數。

import requests

url = "https://example.com"
session = requests.Session()
session.verify = False
cert = ('/path/to/certificate.pem', '/path/to/private_key.pem')
session.cert = cert
response = session.get(url)
print(response)

TLS的其他應用

TLS不僅適用於HTTP協定,也可以用於其他協定,如資料函式庫連線、電子郵件、Telnet、LDAP、FTP等。這些協定的TLS客戶端比瀏覽器更具個性,且其設定更為特定於廠商。接下來,我們將探討兩個超出HTTP的TLS使用案例:資料函式庫連線和電子郵件。

保障資料函式庫連線安全

為了確保資料函式庫連線的安全性,應該使用TLS(Transport Layer Security)加密技術。TLS能夠確保應用程式連線到正確的資料函式庫,並防止資料在傳輸過程中被擷取或竊聽。

在Django中,資料函式庫連線是由框架管理的。每個資料函式庫連線都由一個字典代表,稱為DATABASES。以下是Django中預設的DATABASES設定:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

這個設定使用SQLite作為資料函式庫引擎,並將資料儲存於db.sqlite3檔案中。然而,SQLite並不適合用於生產環境,因為它將資料儲存為明文。

大多數生產環境的Django應用程式都會連線到網路上的資料函式庫。為了連線到資料函式庫,需要提供以下資訊:

  • NAME:資料函式庫名稱
  • HOST:資料函式庫主機名稱或IP地址
  • PORT:資料函式庫連線埠號
  • USER:資料函式庫使用者名稱
  • PASSWORD:資料函式庫使用者密碼

TLS設定則是特定於每個資料函式庫引擎。以下是使用Django連線到PostgreSQL資料函式庫的範例:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'db_name',
        'HOST': 'db_hostname',
        'PORT': 5432,
        'USER': 'db_user',
        'PASSWORD': 'db_password',
        'OPTIONS': {
            'sslmode': 'verify-full',
        },
    }
}

在這個範例中,OPTIONS字典中設定了sslmode引數為verify-full,這表示PostgreSQL客戶端將會驗證伺服器的憑證和主機名稱。

圖表翻譯:

  flowchart TD
    A[應用程式] --> B[資料函式庫連線]
    B --> C[TLS加密]
    C --> D[資料函式庫伺服器]
    D --> E[驗證憑證和主機名稱]
    E --> F[確保資料傳輸安全]

內容解密:

在上述範例中,我們使用Django框架連線到PostgreSQL資料函式庫,並設定TLS加密以確保資料傳輸的安全性。OPTIONS字典中設定的sslmode引數決定了PostgreSQL客戶端的憑證驗證模式。在verify-full模式中,客戶端將會驗證伺服器的憑證和主機名稱,以確保連線到正確的資料函式庫伺服器。

使用TLS加密郵件傳輸

郵件傳輸協定(SMTP)是一種流行的郵件協定,通常使用25號埠。然而,SMTP是一種1980年代的產物,沒有考慮到保密性和身份驗證。攻擊者經常試圖傳送和接收未經授權的郵件,因此郵件伺服器容易受到攻擊。

為了防止網路竊聽者擷取SMTP流量,必須使用SMTPS,即SMTP over TLS。SMTP和SMTPS與HTTP和HTTPS類似。可以使用以下設定升級從SMTP到SMTPS的連線。

###隱含TLS

有兩種方法可以啟動到郵件伺服器的TLS連線。RFC 8314描述了傳統方法為“客戶端建立明文應用會話… 之後是一個TLS握手,可以升級連線”。RFC 8314建議“一個替代機制,其中TLS在連線開始時立即在單獨的埠上進行協商”。建議的機制稱為隱含TLS。

Django的EMAIL_USE_SSLEMAIL_USE_TLS設定可以組態Django以TLS傳送郵件。兩個設定都預設為False,只有一個可以為True,且兩者都不直觀。合理的觀察者會假設EMAIL_USE_TLS優先於EMAIL_USE_SSL。TLS在多年前取代了SSL,具有更好的安全性和效能。然而,隱含TLS是由EMAIL_USE_SSL組態的,而不是EMAIL_USE_TLS

使用EMAIL_USE_TLS比不使用任何東西要好,但如果您的郵件伺服器支援隱含TLS,則應使用EMAIL_USE_SSL。我不知道為什麼EMAIL_USE_SSL不是命名為EMAIL_USE_IMPLICIT_TLS

郵件客戶端身份驗證

與requests包類似,Django的郵件API支援TLS客戶端身份驗證。EMAIL_SSL_KEYFILEEMAIL_SSL_CERTFILE設定代表私鑰和客戶端證書的路徑。兩個選項如果EMAIL_USE_TLSEMAIL_USE_SSL未啟用,則無效。

不要假設每個TLS客戶端都會執行伺服器身份驗證。在撰寫本文時,Django不幸的是在傳送郵件時不會執行伺服器身份驗證。

郵件加密

與您的資料函式庫流量一樣,郵件傳輸中的加密不是郵件本身加密的替代品;兩者都必須做到。最好在郵件傳輸中使用TLS加密,並在郵件本身加密。這樣可以確保郵件的保密性和完整性。

  flowchart TD
    A[郵件傳輸] --> B[SMTP]
    B --> C[SMTPS]
    C --> D[TLS加密]
    D --> E[郵件傳輸]
    E --> F[郵件伺服器]
    F --> G[郵件儲存]
    G --> H[郵件加密]

圖表翻譯:

此圖表示郵件傳輸過程中使用TLS加密和郵件本身加密的流程。郵件傳輸使用SMTP協定,然後升級到SMTPS以啟用TLS加密。加密的郵件傳輸到郵件伺服器,然後儲存在郵件儲存中。郵件儲存使用郵件加密確保郵件的保密性和完整性。

網站安全:HTTPS和TLS的重要性

在網站安全中,HTTPS和TLS是兩個非常重要的概念。HTTPS(Hypertext Transfer Protocol Secure)是一種安全的網頁傳輸協定,它使用TLS(Transport Layer Security)來加密網頁傳輸的資料。TLS是一種業界標準的加密協定,它可以保護網站和使用者之間的資料傳輸。

TLS的工作原理

TLS的工作原理是透過一個叫做TLS握手的過程來建立一個安全的連線。這個過程包括以下幾個步驟:

  1. 客戶端和伺服器之間建立一個連線。
  2. 客戶端和伺服器之間交換TLS版本和加密演算法的資訊。
  3. 客戶端和伺服器之間建立一個分享的金鑰。
  4. 客戶端和伺服器之間使用分享的金鑰來加密和解密資料。

TLS的優點

TLS有以下幾個優點:

  1. 加密: TLS可以加密網站和使用者之間的資料傳輸,保護使用者的敏感資訊。
  2. 身份驗證: TLS可以驗證伺服器的身份,確保使用者正在存取的是正確的網站。
  3. 完整性: TLS可以確保資料傳輸的完整性,防止資料在傳輸過程中被篡改。

Django中的TLS設定

在Django中,TLS設定是透過設定EMAIL_HOST_USEREMAIL_HOST_PASSWORD來實作的。這兩個設定代表SMTP的驗證憑據,SMTP在傳輸過程中不會隱藏這些憑據,除非使用TLS。

以下是Django中設定TLS的示例程式碼:

send_mail('主題',
        '郵件內容',
        auth_user='使用者名稱',
        auth_password='密碼')

這個程式碼設定了SMTP的驗證憑據,從而可以使用TLS來加密郵件的傳輸。

HTTP Sessions 和 Cookies

HTTP sessions 是所有 web 應用程式的基礎,讓伺服器能夠識別每個使用者的流量、內容和狀態。這是所有線上交易的基礎。當使用者存取網站時,伺服器會建立一個 session,並將 session ID 傳送給使用者的瀏覽器。瀏覽器會儲存這個 session ID,並在之後的請求中傳送回給伺服器。

HTTP Sessions 的工作原理

當使用者第一次存取網站時,伺服器會建立一個新的 session,並將 session ID 傳送給瀏覽器。瀏覽器會儲存這個 session ID,並在之後的請求中傳送回給伺服器。伺服器會使用這個 session ID 來識別使用者的 session,並回應相應的內容。

HTTP Cookies

HTTP cookies 是瀏覽器儲存和管理的小型文字資料。伺服器可以建立 cookie,並將其傳送給瀏覽器。瀏覽器會儲存這個 cookie,並在之後的請求中傳送回給伺服器。網站和瀏覽器使用 cookies 來通訊 session ID。

Django 中的 HTTP Sessions

Django 是一個 web 應用程式框架,提供了強大的 HTTP sessions 管理功能。Django 使用 cookies 來儲存和管理 session ID。當使用者存取網站時,Django 會建立一個新的 session,並將 session ID 傳送給瀏覽器。瀏覽器會儲存這個 session ID,並在之後的請求中傳送回給伺服器。

安全性考量

HTTP sessions 和 cookies 的安全性是非常重要的。如果 session ID 被竊取,攻擊者可以使用它來冒充使用者。因此,session ID 應該在 HTTPS 中傳送和接收。Django 提供了預設的安全性設定,防止 session sniffing 和其他攻擊。

# Django 中的 HTTP sessions 示例
from django.contrib.sessions.models import Session

# 建立一個新的 session
session = Session.objects.create()

# 儲存 session ID
session_id = session.session_key

# 將 session ID 傳送給瀏覽器
response = HttpResponse()
response.set_cookie('sessionid', session_id)

圖表翻譯:

  flowchart TD
    A[使用者存取網站] --> B[伺服器建立新的 session]
    B --> C[伺服器將 session ID 傳送給瀏覽器]
    C --> D[瀏覽器儲存 session ID]
    D --> E[瀏覽器在之後的請求中傳送回 session ID]
    E --> F[伺服器使用 session ID 來識別使用者的 session]

網路安全:Cookie 的安全性

Cookie 是網路瀏覽器用來儲存網站資料的機制,當使用者存取網站時,網站可以設定 Cookie 並儲存於使用者的瀏覽器中。然而,Cookie 的安全性是一個重要的問題,因為它可能被用來竊取使用者的敏感資料。

Cookie 的安全性威脅主要來自於中間人攻擊(Man-In-The-Middle,MITM)。中間人攻擊是指攻擊者擷取使用者和網站之間的通訊,竊取使用者的敏感資料,例如 Cookie。這種攻擊可能發生在公用 Wi-Fi 網路或其他不安全的網路環境中。

Secure 指令

為了防止中間人攻擊,網站可以使用 Secure 指令來設定 Cookie。Secure 指令告訴瀏覽器,只有在 HTTPS 通訊中才可以傳送 Cookie。這樣可以防止 Cookie 被擷取和竊取。

Domain 指令

Domain 指令用來控制哪些主機可以接收 Cookie。這個指令可以防止 Cookie 被傳送到不正確的主機,從而防止敏感資料被竊取。

在 Django 中,Cookie 的安全性設定可以透過 SESSION_COOKIE_SECURESESSION_COOKIE_DOMAIN 這兩個設定項來控制。SESSION_COOKIE_SECURE 項用來設定 Secure 指令,SESSION_COOKIE_DOMAIN 項用來設定 Domain 指令。

重要性

Cookie 的安全性設定非常重要,因為它可以防止敏感資料被竊取。特別是在生產環境中,必須確保 SESSION_COOKIE_SECURE 設定為 True,以防止 Cookie 被擷取和竊取。

範例設定

# settings.py
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_DOMAIN = 'example.com'

網站安全:Cookie 和 Session 的管理

Cookie 是小型的文字檔案,儲存於使用者的瀏覽器中,允許網站記住使用者的偏好、登入狀態等資訊。Cookie 的設定和管理對於網站的安全性至關重要。

Domain 指令

Domain 指令用於指定 Cookie 的作用域。它決定了 Cookie 可以被哪些網域存取。這個指令與 SameSite 指令不同,後者決定了 Cookie 的來源。

從系統安全架構的視角來看,本文深入探討了 Django 網站安全性的強化策略,涵蓋 HTTPS、TLS 加密、憑證管理、Cookie 與 Session 安全等關鍵導向。分析指出,雖然 Django 提供了便捷的開發框架,但預設設定並不足以應付生產環境的複雜安全挑戰。要打造堅實的防禦體系,必須仔細組態 HTTPS 和 TLS,正確使用自簽憑證,並強化 Cookie 的安全屬性,例如 Secure 和 Domain 指令,才能有效防禦中間人攻擊和資料洩露。此外,實務上還需考慮 HSTS 標頭和 HTTPS 重定向,以確保所有連線都經由加密通道傳輸。展望未來,隨著網路攻擊手段日益複雜,持續精進安全策略,例如匯入更嚴格的客戶端驗證機制和郵件加密措施,將是保障 Django 網站安全的重要方向。玄貓認為,開發者應將安全意識融入開發流程的每個環節,才能有效防範潛在威脅,為使用者提供安全可靠的線上體驗。