Django 框架虽内置了 XSS 和 CSRF 防御机制,但生产环境中的错误配置或人为绕过常导致漏洞。加固的核心在于确保中间件链路完整、模板转义未被意外关闭以及安全头配置正确。以下方案基于工程实践,涵盖配置、验证及自动化扫描步骤。
先说结论:优先检查中间件链路与模板渲染逻辑,确保默认安全机制未被禁用。
- 先判断:确认 CsrfViewMiddleware 和 SecurityMiddleware 在 MIDDLEWARE 列表中且顺序正确。
- 优先做:生产环境强制关闭 DEBUG 并配置 ALLOWED_HOSTS,表单必须添加 {% csrf_token %}。
- 再验证:通过 curl 命令测试 CSRF 拦截,检查响应头是否包含 Content-Security-Policy。
生产环境核心配置
直接核对 settings.py 关键项,确保基础防护生效。注意中间件顺序,SessionMiddleware 必须在 CsrfViewMiddleware 之前。
# settings.py 关键检查项
DEBUG = False
ALLOWED_HOSTS = ['yourdomain.com', 'www.yourdomain.com']
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
# ... 其他中间件
]
# Cookie 安全传输
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True
SECURE_SSL_REDIRECT = True
# 防止内容嗅探
SECURE_CONTENT_TYPE_NOSNIFF = True配置内容安全策略 (CSP)
现代浏览器已废弃 X-XSS-Protection 头,应优先配置 Content-Security-Policy (CSP) 来防御 XSS。推荐使用 django-csp 包进行管理。
1. 安装依赖
pip install django-csp2. 配置中间件与策略
# settings.py
INSTALLED_APPS = [
# ...
'csp',
]
MIDDLEWARE = [
# ...
'csp.middleware.CSPMiddleware',
]
# 基础 CSP 策略示例
CONTENT_SECURITY_POLICY = {
'DEFAULT_SRC': ("'self'",),
'SCRIPT_SRC': ("'self'",),
'OBJECT_SRC': ("'none'",),
}验证与测试命令
1. 测试 CSRF 防护
使用 curl 模拟不带令牌的 POST 请求,服务器应返回 403 Forbidden。
curl -X POST http://127.0.0.1:8000/login/ -d "username=test&password=test" -v检查响应状态码是否为 403,且响应体包含 CSRF 相关错误信息。
2. 测试 XSS 转义
在输入框提交 <script>alert(1)</script>,页面回显应显示为文本而非执行脚本。同时检查响应头:
curl -I http://127.0.0.1:8000/确认响应头包含 Content-Security-Policy,不再依赖已废弃的 X-XSS-Protection。
3. 确认调试信息关闭
触发服务器错误,确保页面显示自定义错误页,而非 Django 详细调试 traceback 信息。
自动化安全扫描
建议将静态代码分析纳入 CI 流程,使用 Bandit 扫描常见安全问题。
# 安装
pip install bandit
# 扫描项目
bandit -r .重点关注报告中关于 XSS、CSRF 及安全配置的低置信度警告。
常见陷阱与排查
1. 前端 AJAX 请求未带 Token
使用 fetch 或 axios 发送 POST 请求时,需从 Cookie 读取 csrftoken 并设置到请求头 X-CSRFToken 中,否则请求被拦截。
2. 滥用 @csrf_exempt
避免全局使用 @csrf_exempt 装饰器。如果确实需要豁免,优先用 csrf_protect 包裹特定逻辑,而非直接关掉中间件。
3. CSRF_COOKIE_HTTPONLY 设置错误
该值必须为 False,否则 JavaScript 无法读取 Cookie 中的 token,导致 AJAX 请求无法携带令牌。Django 默认即为 False,不要手动改为 True。
4. 中间件顺序错误
SecurityMiddleware 应放在列表较前的位置,而自定义的响应处理中间件应放在后面,否则安全头可能被后续中间件覆盖。