直接硬编码 SECRET_KEY 极其危险,因 Git、Docker、日志、IDE 缓存等均可能泄露;应运行时读取环境变量,禁用 fallback,严格区分环境,正确使用 python-dotenv 按需加载并确保路径准确。

为什么直接在代码里写 SECRET_KEY 很危险
因为 Git 提交、Docker 镜像、服务器日志甚至 IDE 的自动补全缓存,都可能把硬编码的密钥暴露出去。哪怕只在本地测试时写了一次 app.config['SECRET_KEY'] = 'dev-key',一旦误提交到公开仓库,就等于把锁孔照片发到了网上。
真正安全的做法是:运行时读取、不进版本控制、不同环境用不同值。
-
.env文件必须加到.gitignore里(确认它没出现在git status中) - 不要在
__init__.py或app.py里用os.environ.get('SECRET_KEY', 'fallback')直接取值——fallback 值一旦被用上,说明环境变量缺失,此时应该报错退出,而不是降级运行 - Python 3.11+ 的
importlib.resources.files不会自动加载.env,得靠python-dotenv显式加载
如何用 python-dotenv 正确加载配置
不是所有位置调用 load_dotenv() 都有效。它只影响当前进程的 os.environ,且只加载一次(重复调用无副作用)。关键在于加载时机和作用域。
- 在创建 Flask 实例之前调用
load_dotenv(),比如放在app/__init__.py顶部或manage.py入口最开始 - 如果项目结构是
src/app/,需指定路径:load_dotenv(Path(__file__).parent.parent / '.env') - 开发环境默认找
.env,生产环境应禁用自动加载,改由系统级环境变量提供(如 systemd 的EnvironmentFile=或 Docker 的--env-file) -
load_dotenv(verbose=True)可用于调试是否成功读取——看到Found: .env才算到位
Flask 的 config.from_mapping() 和 config.from_object() 怎么选
二者用途完全不同:from_object 是从 Python 模块/类中导入配置项(适合多环境类定义),from_mapping 是直接传字典(适合运行时拼装)。敏感信息必须走环境变量,不能塞进配置类里。
- 错误示范:
class Config: SECRET_KEY = os.getenv('SECRET_KEY', 'dev')—— 这个类一旦被 import,os.getenv就执行了,但此时load_dotenv()可能还没调用 - 正确做法:先
load_dotenv(),再用app.config.from_mapping({'SECRET_KEY': os.environ['SECRET_KEY']}),并确保os.environ中该键存在(用os.environ.get('SECRET_KEY')判空后抛异常) - 如果要用类组织配置,类中只放非敏感常量(如
JSON_SORT_KEYS = False),敏感字段全部延迟到create_app()函数内注入
Docker 部署时 .env 文件为何不生效
Docker 容器启动时,宿主机的 .env 文件默认不会挂载进去,python-dotenv 在容器里根本找不到它。
- 开发时用
docker-compose.yml的env_file:字段显式挂载:env_file: .env(注意:这是 Docker 的机制,和python-dotenv无关) - 生产镜像禁止 COPY
.env文件——构建阶段泄露风险极高;应通过docker run --env-file prod.env或 Kubernetes Secret 注入 - 若坚持用
python-dotenv,需在容器内挂载外部.env到固定路径(如/app/.env),并在代码中指定load_dotenv('/app/.env') - 检查容器内是否真有变量:
docker exec -it myapp printenv | grep SECRET,别只信代码逻辑
最容易被忽略的是:load_dotenv() 默认只读取当前工作目录下的 .env,而 Flask 应用在 Gunicorn 或 uWSGI 下启动时,工作目录可能是 / 或 /var/www,不是项目根目录。务必用绝对路径或基于 __file__ 构造路径。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











