文章

Django - 安全性實踐

安全性是 Web 開發中最重要的方面之一。本節將探討如何在 Django 應用中實現安全性最佳實踐,保護應用免受常見攻擊。


課程目標

  1. 瞭解 Django 的內建安全功能。
  2. 學習如何防範常見的 Web 攻擊(如 XSS、CSRF、SQL 注入)。
  3. 配置安全的 Django 生產環境。
  4. 使用外部工具增強安全性。

課程內容

1. Django 內建安全功能

步驟 1:CSRF 保護

Django 默認啟用 CSRF 保護,防止跨站請求偽造。
在模板中使用 CSRF 標記:

1
2
3
4
5
<form method="post">
  {% csrf_token %}
  <input type="text" name="data" />
  <button type="submit">Submit</button>
</form>

如果需要在非模板中發送 POST 請求(如 Ajax),請添加 CSRF 標記到請求頭:

1
2
3
4
5
6
7
fetch("/api/", {
  method: "POST",
  headers: {
    "X-CSRFToken": getCookie("csrftoken"),
  },
  body: JSON.stringify({ data: "value" }),
});

步驟 2:XSS 保護

Django 模板自動對變數進行 HTML 轉義,防止跨站腳本攻擊(XSS)。
範例:

1
<p>{{ user_input }}</p>

若需顯示未轉義的 HTML,請使用 safe 過濾器(需謹慎使用):

1
<p>{{ user_input|safe }}</p>

步驟 3:SQL 注入防護

Django ORM 自動使用參數化查詢,防止 SQL 注入。
範例:

1
2
3
4
5
# 安全的查詢方式
User.objects.filter(username="example")

# 危險的查詢方式(避免使用)
cursor.execute(f"SELECT * FROM auth_user WHERE username = '{username}'")

步驟 4:密碼管理

Django 使用 PBKDF2 演算法對密碼進行哈希。
範例:

1
2
3
4
from django.contrib.auth.hashers import make_password, check_password

hashed_password = make_password('my_password')
is_valid = check_password('my_password', hashed_password)

可修改哈希演算法:

1
2
3
4
5
6
PASSWORD_HASHERS = [
    'django.contrib.auth.hashers.Argon2PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
    'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
]

2. 防禦常見攻擊

步驟 1:避免敏感數據暴露

確保以下敏感信息不出現在代碼庫中:

  • SECRET_KEY
  • 資料庫憑證
  • 第三方 API 密鑰

將它們存儲在環境變數或 .env 文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import os
from dotenv import load_dotenv

load_dotenv()

SECRET_KEY = os.getenv('DJANGO_SECRET_KEY')
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.getenv('DB_NAME'),
        'USER': os.getenv('DB_USER'),
        'PASSWORD': os.getenv('DB_PASSWORD'),
        'HOST': os.getenv('DB_HOST'),
        'PORT': os.getenv('DB_PORT'),
    }
}

步驟 2:HTTPS 與 HSTS

  • 在生產環境中,強制使用 HTTPS,確保數據加密傳輸。
  • 啟用 HTTP 嚴格傳輸安全(HSTS):
    settings.py 中設置:
1
2
3
4
SECURE_SSL_REDIRECT = True
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True

步驟 3:內容安全策略(CSP)

使用 Django-CSP 強制限制加載的資源來源:

1
pip install django-csp

settings.py 中添加:

1
2
3
4
5
INSTALLED_APPS += ['csp']
CSP_DEFAULT_SRC = ["'self'"]
CSP_SCRIPT_SRC = ["'self'", "cdnjs.cloudflare.com"]
CSP_STYLE_SRC = ["'self'", "fonts.googleapis.com"]
CSP_FONT_SRC = ["fonts.gstatic.com"]

步驟 4:限制登入嘗試

防止暴力破解攻擊:

1
pip install django-axes

settings.py 中:

1
2
3
4
INSTALLED_APPS += ['axes']
MIDDLEWARE += ['axes.middleware.AxesMiddleware']
AXES_FAILURE_LIMIT = 5  # 最大嘗試次數
AXES_COOLOFF_TIME = 1  # 鎖定時間(小時)

3. 生產環境安全配置

步驟 1:關閉 DEBUG 模式

在生產環境中設置:

1
2
DEBUG = False
ALLOWED_HOSTS = ['yourdomain.com']
1
2
3
4
SESSION_COOKIE_SECURE = True  # 僅通過 HTTPS 傳輸
CSRF_COOKIE_SECURE = True     # 僅通過 HTTPS 傳輸
SECURE_BROWSER_XSS_FILTER = True  # 啟用瀏覽器的 XSS 過濾
SECURE_CONTENT_TYPE_NOSNIFF = True  # 禁止 MIME 嗅探

步驟 3:屏蔽敏感信息

在錯誤頁面中隱藏敏感信息:

1
DEBUG_PROPAGATE_EXCEPTIONS = False

4. 安全工具

工具推薦

  • OWASP ZAP:檢測應用漏洞。
  • Sentry:錯誤跟蹤和安全事件記錄。
  • django-secure:額外的安全性檢查。

Sentry 集成

1
pip install sentry-sdk

settings.py 中:

1
2
3
4
5
6
7
8
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration

sentry_sdk.init(
    dsn="your_sentry_dsn",
    integrations=[DjangoIntegration()],
    send_default_pii=True,
)

課堂練習

  1. 改進 Day 7 的 Blog 應用:
    • 為所有表單添加 CSRF 保護。
    • 使用 CSP 限制資源來源。
    • 限制登入失敗次數,防止暴力破解。

作業

  1. 為應用啟用 HTTPS 和 HSTS,並測試效果。
  2. 使用 OWASP ZAP 對應用進行掃描,修復檢測到的安全漏洞。
  3. 配置 Sentry,實時監控應用錯誤和安全事件。

本文章以 CC BY 4.0 授權