Django 初學者指南:ALLOWED_HOSTS 設定與安全性考量
更新日期: 2025 年 3 月 13 日
本文為 HTTPS 連線 基本介紹,第 6 篇:
- 什麼是代管網域(Domain Hosting)?初學者完整指南
- 網站託管(Web Hosting)入門指南:讓你的網站輕鬆上線
- Cloudflare 介紹:讓網站更安全、更快速的關鍵服務
- 反向代理是什麼?初學者必看詳解
- Apache HTTP Server 是什麼:初學者指南
- Django 初學者指南:ALLOWED_HOSTS 設定與安全性考量 👈進度
- 如何為初學者配置 HTTPS 和 SSL:Cloudflare、Let’s Encrypt 和 Apache 完整指南
- Let’s Encrypt 初學者完全指南
- 虛擬主機(Virtual Host)入門指南:讓你的網站輕鬆上線
- 初學者指南:設定 Apache 反向代理 Django 服務(含 SSL)
- Cloudflare 設定指南:如何正確配置 SSL/TLS 加密模式
- Cloudflare Edge Certificates 入門指南
- 解決 Cloudflare 301 重定向循環問題:初學者指南
Django 是一個強大的 Web 框架,但在部署時,安全性設定至關重要。
其中,ALLOWED_HOSTS
是 Django 預設的安全機制之一,它能有效防止 HTTP Host Header 攻擊。
然而,許多初學者在部署 Django 至 GCP 或其他雲端平台時,對於如何正確設定 ALLOWED_HOSTS
感到困惑。
本篇文章將詳細介紹 ALLOWED_HOSTS
的概念、風險、防範措施,以及如何在 GCP 環境中透過 Docker Compose 和環境變數來管理這個設定。
什麼是 ALLOWED_HOSTS?
ALLOWED_HOSTS
是 Django 設定檔 settings.py
中的一項安全機制,主要用來防範 HTTP Host Header 攻擊。
它的作用是檢查 來自用戶端的請求中 Host
標頭 (Host Header) 是否在允許的清單內,從而確保只有經過授權的網域或 IP 地址才能存取 Django 應用。
當 Django 伺服器收到 HTTP 請求時,它會解析請求標頭中的 Host
欄位,並與 ALLOWED_HOSTS
內的清單進行比對:
- 若
Host
在ALLOWED_HOSTS
清單內,請求將被接受並繼續處理。 - 若
Host
不在清單內,Django 會立即返回 400 Bad Request,防止進一步處理請求。
基本範例
在 settings.py
中,我們可以這樣設定 ALLOWED_HOSTS
:
ALLOWED_HOSTS = ['example.com', 'www.example.com', '34.123.45.67', 'localhost']
這表示:
- Django 允許 來自
example.com
和www.example.com
的請求。 - 允許使用指定的 IP 地址
34.123.45.67
直接存取。 - 允許在 本機環境 (
localhost
) 中存取,例如開發環境的測試請求。 - 任何 不在
ALLOWED_HOSTS
清單中的請求都會被拒絕,並回應 400 Bad Request。
為什麼需要 ALLOWED_HOSTS?
ALLOWED_HOSTS
主要用來防止 HTTP Host Header 攻擊,這是一種針對 Web 伺服器的攻擊手法,攻擊者可以透過 偽造 Host
標頭 來達成不同的攻擊目的。例如:
不安全的重定向 (Open Redirect) 攻擊
情境說明
假設你的 Django 網站有一個 登入成功後的重定向功能,它會把使用者導向首頁 (/home/
)。程式碼可能如下:
from django.http import HttpResponseRedirect
def redirect_to_home(request):
return HttpResponseRedirect(f"https://{request.get_host()}/home/")
在這段程式碼中,request.get_host()
會取得 HTTP 請求中的 Host 標頭 (Host Header),然後組合成重定向的 URL。
攻擊方式
攻擊者可以發送一個 偽造的 Host 標頭,例如:
GET / HTTP/1.1
Host: attacker.com
Django 在沒有嚴格檢查 Host 的情況下,會根據這個偽造的 Host
產生以下重定向網址:
https://attacker.com/home/
然後,當 Django 把這個網址發送回用戶時:
- 用戶的瀏覽器會 自動導向
attacker.com/home/
。 attacker.com
可能是一個 釣魚網站,它的畫面看起來跟你的網站很像,讓用戶以為自己仍然在官方網站上。- 用戶可能會在攻擊者網站輸入帳號密碼,從而洩露個人資料。
如何防範?
在 settings.py
中設定 ALLOWED_HOSTS
,讓 Django 只接受指定的 Host:
ALLOWED_HOSTS = ['example.com', 'www.example.com']
這樣,當攻擊者偽造 attacker.com
時,Django 會直接返回 400 Bad Request,阻止攻擊發生。
生成錯誤的絕對 URL
情境說明
假設你的 Django 應用程式有 密碼重設功能,會在寄送郵件時提供一個網址讓用戶點擊來重設密碼:
def get_password_reset_url(request):
absolute_url = f"https://{request.get_host()}/reset-password/"
return absolute_url
在這段程式碼中:
request.get_host()
取得Host
標頭 (例如example.com
)。- 然後組合出
https://example.com/reset-password/
,讓用戶點擊重設密碼。
攻擊方式
攻擊者發送一個帶有偽造 Host
的 HTTP 請求:
GET / HTTP/1.1
Host: fakebank.com
Django 沒有檢查 Host,所以會錯誤地產生:
https://fakebank.com/reset-password/
這個錯誤的 URL 可能會出現在:
- Django 自動發送的 密碼重設郵件。
- 應用程式內部的 UI 按鈕,例如「重設密碼」。
當用戶收到這封郵件,點擊 https://fakebank.com/reset-password/
:
- 他會進入攻擊者控制的網站 (
fakebank.com
)。 - 這個網站可能會顯示一個 與原站相似的登入頁面,誘導用戶輸入密碼。
- 用戶輸入的密碼就會直接傳送給攻擊者,造成帳號洩露。
如何防範?
在 settings.py
中設定 ALLOWED_HOSTS
,讓 Django 只允許合法的 Host:
ALLOWED_HOSTS = ['example.com', 'www.example.com']
此外,在產生網址時,避免使用 request.get_host()
,而是硬編碼官方網站的網域:
def get_password_reset_url():
return "https://example.com/reset-password/"
這樣,不管攻擊者如何偽造 Host
,Django 產生的密碼重設連結都會是 正確的官方網址。
綜合比較
攻擊類型 | 攻擊手法 | 風險 | 防範方式 |
---|---|---|---|
不安全的重定向 (Open Redirect) | 偽造 Host,讓 Django 產生錯誤的跳轉網址 | 用戶被導向釣魚網站,可能洩露帳號密碼 | 設定 ALLOWED_HOSTS 限制合法的 Host |
生成錯誤的絕對 URL | 偽造 Host,讓 Django 產生錯誤的網站連結 | 釣魚攻擊,誘導用戶點擊錯誤的密碼重設連結 | 設定 ALLOWED_HOSTS,避免使用 request.get_host() 生成 URL |
Django 如何判斷請求是否合法?
當使用者在瀏覽器中輸入 http://example.com
時,請求的處理流程如下:
瀏覽器發送 HTTP 請求
瀏覽器向伺服器發送請求時,會在 HTTP 標頭中包含 Host
欄位,例如:
GET / HTTP/1.1
Host: example.com
Django 伺服器檢查 ALLOWED_HOSTS
Django 伺服器收到請求後,會執行以下檢查:
- 如果
example.com
在ALLOWED_HOSTS
,請求被接受並繼續處理。 - 如果
Host
不在ALLOWED_HOSTS
清單內,Django 直接回應400 Bad Request
,請求終止。
ALLOWED_HOSTS 只影響 HTTP 層,不影響網路層
在 Django 的安全機制中,ALLOWED_HOSTS
僅適用於 HTTP 層,它的作用是檢查請求的 Host
標頭 (Host Header) 是否在允許的清單中。
然而,它不會影響伺服器的網路層存取權限,這一點非常重要。
什麼是網路層與 HTTP 層?
在網路架構中,我們可以將 Django 伺服器的存取控制分為 網路層 (Network Layer) 和 HTTP 層 (Application Layer) 來理解:
- 網路層 (Network Layer)
- 控制誰可以連接到伺服器的 IP 地址 和 Port (端口)。
- 例如,防火牆規則 (
iptables
、GCP 防火牆) 可用來限制哪些 IP 可以連線到伺服器的 80 (HTTP) 或 443 (HTTPS) 端口。
- HTTP 層 (Application Layer)
- 這一層發生在 TCP 連線已經建立之後,處理 HTTP 請求的內容。
ALLOWED_HOSTS
屬於 HTTP 層,它不會阻擋連線,而是檢查請求中的Host
標頭,確保 Django 只回應來自合法網域的請求。
ALLOWED_HOSTS 不影響 TCP 連線
由於 ALLOWED_HOSTS
只檢查 HTTP Host
標頭,而不會影響網路層的存取,這意味著:
- 任何知道伺服器 IP 地址 的人都可以嘗試向 Django 伺服器發送 HTTP 請求。
- 但 Django 不一定會回應這些請求,因為它會先檢查
ALLOWED_HOSTS
。
舉例說明
假設你的 Django 伺服器運行在 GCP VM 上,並且你的 ALLOWED_HOSTS
只允許你的官方域名:
ALLOWED_HOSTS = ['example.com']
這代表 Django 只會回應來自 example.com
的請求。
情境 1:正常請求
使用者在瀏覽器輸入:
http://example.com
瀏覽器會發送請求:
GET / HTTP/1.1
Host: example.com
Django 會檢查 Host
,發現 example.com
在 ALLOWED_HOSTS
清單內,因此接受請求並回應正常的 HTTP 內容。
情境 2:攻擊者直接用 IP 存取
假設攻擊者知道了你的 GCP 伺服器的 IP,例如 34.123.45.67
,並嘗試直接使用 IP 進行請求:
http://34.123.45.67
攻擊者的請求如下:
GET / HTTP/1.1
Host: 34.123.45.67
Django 會進行 ALLOWED_HOSTS
檢查:
34.123.45.67
不在ALLOWED_HOSTS
清單內。- Django 直接回應 400 Bad Request,拒絕處理該請求。
但需要注意的是:
- 攻擊者的請求仍然會到達你的伺服器,只是 Django 不會回應內容。
- 如果伺服器上運行的不是 Django,而是其他應用程式 (如 Nginx),該應用程式仍可能處理請求。
如何加強安全性?
雖然 ALLOWED_HOSTS
能防止 Django 回應未授權的 Host
,但它無法阻止攻擊者與伺服器建立 TCP 連線。因此,建議額外採取以下措施來提升安全性:
1. 設定防火牆,限制 IP 存取
在 GCP 或其他雲端平台上,可以設定防火牆 只允許特定 IP 或 Cloudflare Proxy 來存取 Django 伺服器:
- 在 GCP 防火牆規則 中,設定 只允許 80 (HTTP) 和 443 (HTTPS) 來自 Cloudflare IP 的存取,其他 IP 則封鎖。
- 在 Linux 伺服器上使用
iptables
,只允許來自特定 IP 的連線:
sudo iptables -A INPUT -p tcp --dport 80 -s 203.0.113.0/24 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -s 203.0.113.0/24 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 80 -j DROP
sudo iptables -A INPUT -p tcp --dport 443 -j DROP
- 這樣,只有來自
203.0.113.0/24
(例如 Cloudflare) 的請求能夠進入伺服器。
2. 使用反向代理 (Nginx) 來過濾 Host
你可以使用 Nginx 作為反向代理,並在 Nginx 設定檔 (nginx.conf
) 中 只允許特定 Host
,將不符合條件的請求直接拒絕:
server {
listen 80;
server_name example.com www.example.com;
if ($host !~* ^(example\.com|www\.example\.com)$ ) {
return 444;
}
location / {
proxy_pass http://127.0.0.1:8000;
}
}
這樣,來自 非 example.com
的請求會直接被 Nginx 丟棄 (返回 HTTP 444),根本不會傳到 Django。
總結
安全機制 | 作用範圍 | 限制效果 |
---|---|---|
GCP 防火牆 (firewall rules) | 網路層 (TCP/IP) | 控制哪些 IP 可以連接到伺服器 |
Nginx 反向代理 | HTTP 層 | 只允許特定 Host 進入 Django |
Django ALLOWED_HOSTS | HTTP 層 | 只允許 Django 回應合法 Host 的請求 |
ALLOWED_HOSTS
只影響 HTTP 應用層,它無法阻擋來自任何來源的 TCP 連線,但能確保 Django 只回應合法的Host
。- 如果要完全避免攻擊者直接存取伺服器 IP,應該搭配 GCP 防火牆 或 Linux
iptables
限制 IP 存取。 - 若使用 Nginx,還可以額外設定
server_name
來過濾Host
,進一步增強安全性。
這樣,你的 Django 伺服器才能真正安全地運行在雲端環境中! 🚀
常見錯誤與最佳實踐
在設定 ALLOWED_HOSTS
時,許多初學者會犯一些常見錯誤,例如 錯誤的格式、暴露伺服器 IP,或是 硬編碼設定,這些都可能影響 Django 應用的正常運行與安全性。
以下是常見錯誤與正確的最佳做法,幫助你確保 Django 部署時的安全性與靈活性。
錯誤:包含 http://
或 https://
許多初學者誤以為 ALLOWED_HOSTS
需要包含完整的 URL,例如:
# ❌ 錯誤的設定:
ALLOWED_HOSTS = ['https://example.com', 'http://www.example.com']
這樣的設定會導致 Django 直接回應 400 Bad Request,因為 ALLOWED_HOSTS
只比對 Host
標頭,而 HTTP Host 標頭不包含 http://
或 https://
。
🔎 為什麼會錯?
在 HTTP 通訊協議中,請求的 Host
標頭只包含主機名稱 (域名或 IP),不包含協議 (protocol)。舉例來說,當用戶請求 https://example.com
時,實際的 HTTP 請求是:
GET / HTTP/1.1
Host: example.com
如果 ALLOWED_HOSTS
設定為 ['https://example.com']
,Django 會比對 Host
為 "https://example.com"
,但請求的 Host
只有 "example.com"
,因此匹配失敗,導致 400 錯誤。
為什麼 HTTP Host
標頭不包含 http://
?
當客戶端發送 HTTP 或 HTTPS 請求時,請求的 第一行 (請求行, Request Line) 會包含:
GET /index.html HTTP/1.1
而 Host
標頭則只會包含主機名稱,例如:
Host: example.com
不會是:
Host: https://example.com ❌(錯誤)
為什麼 Host
不包含 http://
或 https://
?
- 因為 HTTP 層不負責協議 (Protocol) 的選擇
- 協議 (
http://
或https://
) 早在 TCP 建立連線時就已經確定了。 - 如果是 HTTPS,瀏覽器會先建立 TLS 安全通道,之後的 HTTP 請求會直接在加密通道內傳輸,因此
Host
無需再指定https://
。
- 協議 (
- HTTP
Host
只用來識別伺服器的名稱- 伺服器可能會託管多個網站,例如:
server { listen 80; server_name example.com; }
在這種情況下,Host: example.com
讓伺服器知道該回應example.com
這個站點,而不是其他網站 (如another-site.com
)。
- 伺服器可能會託管多個網站,例如:
哪個協議負責處理 http://
和 https://
?
HTTP 本身不處理 http://
或 https://
,而是由 瀏覽器或客戶端應用程式 根據使用者輸入的網址來決定:
- 如果輸入
http://example.com
,則 使用 HTTP,連接到 80 端口。 - 如果輸入
https://example.com
,則 使用 HTTPS,連接到 443 端口,並觸發 TLS 加密協議 來確保安全性。
這裡有三個主要負責的協議層:
- TCP/IP (網路層):建立與伺服器的連線。
- TLS (安全層, 只有 HTTPS 會用到):提供加密與身份驗證。
- HTTP (應用層):傳輸網頁內容,處理請求與回應。
因此,當 Django 在 ALLOWED_HOSTS
中檢查 Host 時,它處理的是 HTTP 層,而 http://
或 https://
的部分已經在較低層的協議中處理完畢了。
Host
在 HTTPS 連線中的特殊情況
當 Django 檢查 ALLOWED_HOSTS
時,它不會知道請求來自 http
或 https
,因為:
- 如果是 HTTP,請求直接傳遞給 Django,
Host
只會是example.com
。 - 如果是 HTTPS,請求已經先通過 TLS 加密通道,Django 依然只會收到
example.com
,不會看到https://
。
但有一個例外: 如果你的 Django 伺服器運行在 反向代理 (如 Nginx) 之後,而 Nginx 處理 HTTPS,則 Django 只會收到來自 Nginx 的 HTTP 請求。
這時,你可以在 Django 設定 SECURE_PROXY_SSL_HEADER
來確保 Django 知道請求原本是 HTTPS:
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
這樣,即使 Django 只看到 HTTP,它仍然能知道最初的請求是否來自 HTTPS。
綜合比較
層級 | 作用 | 負責處理 http:// / https:// 嗎? |
---|---|---|
應用層 (HTTP) | 負責處理請求 (如 GET /index.html),檢查 Host。 | ❌ 否,Host 只會包含域名 (如 example.com) |
安全層 (TLS/SSL, 只有 HTTPS 會用到) | 確保加密傳輸,提供身份驗證。 | ✅ 是,負責 HTTPS 的加密與驗證 |
傳輸層 (TCP) | 建立 TCP 連線 (80 = HTTP,443 = HTTPS)。 | ✅ 是,透過端口決定使用 HTTP 或 HTTPS |
網路層 (IP) | 負責資料封包的傳輸。 | ❌ 否,IP 只知道要發送資料到哪台機器 |
正確做法:只填入域名或 IP
設定時應該只填入主機名稱 (域名或 IP),而不是完整的 URL:
# ✅ 正確的設定:
ALLOWED_HOSTS = ['example.com', 'www.example.com', '34.123.45.67']
這樣 Django 就能正確比對 Host
,避免錯誤。
使用環境變數管理 ALLOWED_HOSTS
在 Docker 環境 或 雲端部署 (如 GCP、AWS) 時,最佳做法是使用環境變數來管理 ALLOWED_HOSTS
,避免將設定硬編碼在 settings.py
,提高靈活性。
步驟 1:在 settings.py
讀取環境變數
import os
ALLOWED_HOSTS = os.getenv('DJANGO_ALLOWED_HOSTS', '').split(',')
這樣,Django 會從系統環境變數 DJANGO_ALLOWED_HOSTS
讀取設定,並解析為一個列表。
步驟 2:在 .env
檔案中設定 ALLOWED_HOSTS
在 .env
檔案 (用於 Docker 或 docker-compose
) 中定義:
DJANGO_ALLOWED_HOSTS=example.com,www.example.com
步驟 3:在 docker-compose.yml
中載入環境變數
如果你的 Django 應用運行在 Docker Compose,可以在 docker-compose.yml
內這樣載入 .env
:
version: '3'
services:
web:
image: my-django-app
env_file:
- .env
這樣,你可以輕鬆修改 .env
來更改 ALLOWED_HOSTS
,而不必手動編輯 settings.py
,避免硬編碼帶來的維護困難與安全風險。
如何避免暴露伺服器的 IP?
當你將 Django 應用程式部署到雲端 (如 GCP、AWS、Azure),你可能會遇到這樣的問題:
該如何設定 ALLOWED_HOSTS
,才能允許正常使用者存取,但同時避免攻擊者直接使用伺服器的 IP 來攻擊你的網站?
許多初學者可能會直接將伺服器的 公網 IP 加入 ALLOWED_HOSTS
,例如:
# ❌ 直接暴露伺服器的 IP
ALLOWED_HOSTS = ['34.123.45.67']
這樣的設定存在安全風險,讓我們來看看為什麼這麼做不好,以及如何更安全地管理 ALLOWED_HOSTS
。
為什麼直接暴露伺服器 IP 會有風險?
1️⃣ 攻擊者可以直接使用 IP 存取伺服器
當你將 Django 應用程式的 公網 IP 設為 ALLOWED_HOSTS
,表示只要攻擊者知道你的 IP,他就可以直接透過 IP 存取你的網站,例如:
http://34.123.45.67/
這可能會導致以下問題:
- 繞過你的域名安全性措施
如果你的網站透過 Cloudflare 或 Nginx 作為防護層,但允許直接用 IP 存取,那麼攻擊者可以繞過這些保護機制,直接攻擊你的 Django 伺服器。 - 容易成為掃描攻擊目標
許多駭客會使用工具 (如Shodan
、nmap
、Zmap
) 掃描公網上的伺服器 IP,尋找開放的端口 (如 80、443) 來進行攻擊。如果你的 IP 被掃描到,攻擊者可能會:- 暴力破解管理後台
- 發動 DDoS 攻擊
- 利用已知的 Django 漏洞進行入侵
- 可能洩露內部開發環境
如果你的開發環境或測試環境也使用這個 IP,攻擊者可能會存取尚未正式公開的功能,甚至找到未經保護的 API 端點。
2️⃣ 如果你的伺服器 IP 變更了,Django 設定就會失效
當你將 固定的 IP 設為 ALLOWED_HOSTS
,你的 Django 伺服器只能接受來自該 IP 的請求。然而,在雲端環境 (如 GCP、AWS) 中:
- 你的 公網 IP 可能會變動 (如果沒有設定靜態 IP)。
- 如果你使用 自動擴展 (Auto Scaling) 或負載平衡 (Load Balancer),你的 IP 可能會隨機變動。
這時候,你的 ALLOWED_HOSTS
可能會失效,導致網站無法正常運行,因為 Django 會拒絕來自新 IP 的請求。
如何避免暴露伺服器的 IP?
1️⃣ 使用網域名稱,而非直接使用 IP
最佳做法是 使用網域名稱 來設定 ALLOWED_HOSTS
,而不是直接填入 IP。例如:
# ✅ 只允許透過域名存取
ALLOWED_HOSTS = ['mywebsite.com', 'www.mywebsite.com']
這樣即使你的伺服器 IP 變更了,只要你的 網域 DNS 指向最新的 IP,Django 就可以繼續運行,而不需要手動修改 settings.py
。
如何設定?
- 購買網域 (例如
mywebsite.com
)。 - 設定 DNS 解析,將
mywebsite.com
指向你的 GCP VM 公網 IP。 - 確認
ALLOWED_HOSTS
只包含你的域名,避免直接使用 IP。
2️⃣ 透過反向代理 (Nginx) 隱藏後端 IP
如果你希望避免伺服器 IP 直接暴露在網路上,你可以使用 Nginx 作為反向代理,讓 Django 只能接受來自 Nginx 的請求,而不是來自外部的 IP 直接存取。
步驟
- 在 Nginx 設定
server_name
,只允許特定網域存取
server {
listen 80;
server_name mywebsite.com www.mywebsite.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
}
}
- 在 Django 設定
ALLOWED_HOSTS
,確保只接受來自正確的網域
ALLOWED_HOSTS = ['mywebsite.com', 'www.mywebsite.com']
- 封鎖對 Django 內部服務 (Gunicorn) 的直接存取
- 透過 防火牆 (iptables/GCP Firewall Rules) 限制 Django 只接受來自 Nginx (127.0.0.1) 的請求。
這樣,所有外部請求都必須透過 Nginx 來存取 Django,攻擊者無法直接用 IP 存取 Django 伺服器。
3️⃣ 使用環境變數來管理 ALLOWED_HOSTS
如果你的 Django 應用部署在 多個環境 (如開發環境、測試環境、正式環境),而且你不想手動修改 settings.py
,你可以使用 環境變數 來動態設定 ALLOWED_HOSTS
。
這樣即使你的伺服器 IP 或域名變更了,你只需要修改環境變數即可。
步驟
- 在
settings.py
讀取環境變數
import os
ALLOWED_HOSTS = os.getenv('DJANGO_ALLOWED_HOSTS', '').split(',')
- 在
.env
或docker-compose.yml
設定環境變數
DJANGO_ALLOWED_HOSTS=mywebsite.com,www.mywebsite.com
- 在 Docker 或雲端環境載入環境變數
version: '3'
services:
web:
image: my-django-app
env_file:
- .env
這樣,你的 ALLOWED_HOSTS
會根據 .env
設定動態變更,而不需要修改程式碼。
總結
錯誤做法 | 風險 | 正確做法 |
---|---|---|
ALLOWED_HOSTS = ['https://example.com'] | Django 無法匹配 Host,導致 400 錯誤 | ALLOWED_HOSTS = ['example.com'] |
ALLOWED_HOSTS = ['34.123.45.67'] | 伺服器 IP 直接暴露,易受攻擊 | ALLOWED_HOSTS = ['mywebsite.com'] |
在 settings.py 硬編碼 ALLOWED_HOSTS | 變更時需要修改程式碼,難以維護 | 使用環境變數 (os.getenv()) |
- ✅ 不要在
ALLOWED_HOSTS
中包含http://
或https://
,只填入主機名稱 (域名或 IP)。 - ✅ 使用 DNS 解析,避免直接暴露伺服器 IP。
- ✅ 搭配 Nginx 作為反向代理,隱藏後端伺服器 IP,提升安全性。
- ✅ 透過環境變數設定
ALLOWED_HOSTS
,提升靈活性,避免硬編碼帶來的問題。
透過這些最佳實踐,你可以讓 Django 應用更安全、更靈活,避免潛在的攻擊與運維風險!🚀
在 GCP 搭配 Docker Compose 執行 Django
如果你使用 Google Cloud Platform (GCP) 部署 Django,且透過 Docker Compose 運行,建議透過 環境變數 設定 ALLOWED_HOSTS
,確保靈活性與安全性。
設定方式
- 建立
.env
檔案DJANGO_ALLOWED_HOSTS=mywebsite.com,www.mywebsite.com
- 在
docker-compose.yml
中載入環境變數version: '3' services: web: image: my-django-app env_file: - .env
- 在
settings.py
中讀取環境變數import os ALLOWED_HOSTS = os.getenv('DJANGO_ALLOWED_HOSTS', '').split(',')
這樣,你可以透過 .env
來動態調整 ALLOWED_HOSTS
,而不需要修改 settings.py
內的程式碼。
GCP VM 上如何正確設定 ALLOWED_HOSTS?
如果你的 Django 應用是直接部署在 GCP VM 上,而非透過 Docker,可以透過 域名 來管理 ALLOWED_HOSTS
。
步驟
- 在 GCP 設定靜態 IP
- 確保 GCP VM 有一個固定的外部 IP,然後將該 IP 綁定至網域。
- 設定 DNS 解析
- 在 Cloud DNS 或第三方 DNS 供應商(如 Cloudflare)中,將
mywebsite.com
指向 GCP VM 的靜態 IP。
- 在 Cloud DNS 或第三方 DNS 供應商(如 Cloudflare)中,將
- 在
settings.py
中使用域名ALLOWED_HOSTS = ['mywebsite.com', 'www.mywebsite.com']
避免常見錯誤
- 不要在
ALLOWED_HOSTS
中包含http://
或https://
# ❌ 錯誤 ALLOWED_HOSTS = ['https://mywebsite.com'] # ✅ 正確 ALLOWED_HOSTS = ['mywebsite.com']
- 若使用反向代理 (如 Nginx),確保轉發的 Host 不變
- 在 Nginx 配置
proxy_set_header Host $host;
以確保 Django 能正確檢查 Host。
- 在 Nginx 配置
總結
ALLOWED_HOSTS
用來限制哪些 Host 可以存取 Django 應用,防止 HTTP Host Header 攻擊。- 盡量使用 網域名稱,而非直接使用 IP 地址,來降低風險。
- 在 GCP 或 Docker 環境中,可以透過 環境變數 設定
ALLOWED_HOSTS
,提高彈性與安全性。 - 在 GCP VM 部署時,應設定 靜態 IP,並搭配 DNS 解析,確保域名解析正常運作。
希望這篇文章能幫助你更好地理解 ALLOWED_HOSTS
的作用與最佳設定方式,讓你的 Django 應用更安全!🚀