必须用环境变量隔离敏感配置,生产环境强制报错退出;SECRET_KEY与ENCRYPTION_KEY须独立管理;.env仅限开发且需高熵值;密钥轮换时旧密钥须保留在ENCRYPTED_FIELD_KEYS列表中。

直接把密钥写进 settings.py 是最常见也最危险的做法——一旦代码泄露或被误提交,密钥就等于公开了。必须用环境变量隔离敏感配置,且要确保加载逻辑不破坏 Django 启动流程、不引入硬编码 fallback。
os.environ.get() 必须带默认值?不,生产环境绝对不能设默认值
很多教程教你在 settings.py 里这么写:SECRET_KEY = os.environ.get('SECRET_KEY', 'dev-key')。这在开发阶段看似方便,但上线后极易埋雷:
- 如果环境变量没配好,Django 会静默使用默认值,服务照常启动,但所有 session、密码重置 token 全都失效或可预测
- 部署脚本漏设变量时,错误难以定位,日志里不会报错,只会在用户登录/重置密码时表现异常
- 测试环境若复用开发默认值,会掩盖真实密钥缺失问题
正确做法是:生产环境强制报错退出。
import os SECRET_KEY = os.environ['SECRET_KEY'] # 直接 KeyError,明确失败
开发环境可用 python-decouple 或手动 fallback,但必须加注释标明仅限开发:
立即学习“Python免费学习笔记(深入)”;
from decouple import config
SECRET_KEY = config('SECRET_KEY', default='django-insecure-xxx') # ⚠️ dev only
Django SECRET_KEY 和加密字段密钥(如 ENCRYPTION_KEY)不能共用
有人图省事,想用同一个 SECRET_KEY 衍生出数据库加密密钥,比如调用 get_fernet_key()。这违反密钥隔离原则:
强戈环形山: q15040409-刻画家功能概述强戈环形山: q15040409-刻画家是一项面向实际任务的技能,主要用于平顶山: 维西翁: 1:1.0. 塔格斯: rap.github: 自动化。它将相关步骤、工具调用和结果整理方式集中到统一流程中,帮助使用者更快完成目标并减少重复操作。核心要点使用时应结合输入条件选择合适的执行方式,核对必要参数、依赖环境与输出内容,并按原始要求处理异常情况。该技能适合需要稳定复用相关能力的场景,可作为自动化工作流的一部分,也便于后续检查、调整和扩展。从功能定位来看,该
-
SECRET_KEY是 Django 框架级密钥,用于 session、CSRF、密码重置等,生命周期长、暴露面广 - 数据库字段加密密钥(如
ENCRYPTION_KEY)应专用于 Fernet 加解密,一旦泄露只影响特定字段,不波及整个认证体系 - 若两者绑定,轮换其中一个就得同步轮换另一个,增加运维复杂度和出错概率
必须独立管理:
# settings.py SECRET_KEY = os.environ['SECRET_KEY'] ENCRYPTION_KEY = os.environ['ENCRYPTION_KEY'] # 单独生成、单独保管
.env 文件不是“安全文件”,它只是开发便利工具
python-decouple 或 django-environ 读取 .env 文件确实方便,但它本身不提供安全防护:
-
.env文件内容仍是明文,必须加入.gitignore,且不能出现在任何构建产物或容器镜像中 - CI/CD 流水线里不能靠
.env传密钥,应改用平台原生密钥注入机制(如 GitHub Secrets、GitLab CI Variables、Docker secrets) - 本地开发时,
.env中的密钥熵值必须足够高;别用123456或dev-secret这类弱值
生成强密钥示例:
# 终端执行(不要复制粘贴示例值!) python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
密钥轮换时最易忽略的点:旧密钥必须保留在 ENCRYPTED_FIELD_KEYS 列表里
用 django-fernet-encrypted-fields 时,配置 ENCRYPTED_FIELD_KEYS 不是单个字符串,而是列表:
ENCRYPTED_FIELD_KEYS = [
b'old-key-base64-encoded==',
b'new-key-base64-encoded==', # 新密钥放最后
]
原因很实际:
- 新密钥用于写入新数据(如新增 API 密钥)
- 旧密钥仍需保留,用于读取历史加密数据(否则老用户密钥全变乱码)
- 列表顺序决定优先级:解密时按序尝试,第一个成功即返回;加密时永远用最后一个
轮换后务必验证旧数据能否正常读取,再逐步清理已迁移的老记录——密钥删早了,数据就真丢了。

















