加密字段必须继承models.field并重写from_db_value、to_python、get_prep_value方法,用cryptography的fernet实现自动加解密,密钥须由环境变量注入且全生命周期不变。

加密字段必须用自定义Field而非在Model.save()里手动处理
直接在 save() 方法里对字段值做加解密,会导致查询失效、ORM缓存异常、admin界面显示明文等问题。Django的查询机制(如 filter(name__contains="abc"))依赖字段原始值参与SQL生成,手动加密会破坏这一链条。真正可行的方式是继承 models.Field,重写 from_db_value()、to_python()、get_prep_value() 三个方法,让加解密在数据进出数据库时自动发生。
关键点:
-
get_prep_value():把Python值(如字符串)加密后转为可存入数据库的类型(通常是bytes或str,推荐 base64 编码后的str) -
from_db_value():从数据库读出加密数据后,解密并返回原始Python值 -
to_python():处理反序列化、表单提交等场景下的值转换,也需解密 - 必须设置
description = "Encrypted text field",否则迁移时可能报错
推荐用cryptography库的Fernet实现对称加密,别手写AES逻辑
Fernet 是基于 AES-128-CBC 的高封装方案,自带密钥派生、随机IV、消息认证(HMAC),避免开发者踩IV复用、padding错误、认证缺失等致命坑。硬编码密钥或用 os.urandom(32) 临时生成都不可取——密钥必须由环境变量或密钥管理服务注入,且全生命周期保持不变。
实操要点:
- 密钥必须是
base64.urlsafe_b64encode()编码的32字节随机密钥,例如:YQsZz7VxKj9LmNpRtWvXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcD== - 在
settings.py中通过os.environ.get("ENCRYPTION_KEY")获取,绝不写死在代码里 - 每次加密都会生成新IV,所以同一明文多次加密结果不同——这是正常行为,不是bug
- 不要用
hashlib或pycrypto(已弃用),cryptography是当前唯一推荐的底层库
ForeignKey、JSONField、DateTimeField 等不能直接加密,需拆解或换方案
加密只适用于纯文本/二进制字段(如 CharField、TextField)。对 ForeignKey 加密外键ID?不行——数据库外键约束和JOIN将彻底失效;对 JSONField 整体加密?可以,但失去JSON路径查询能力(如 data__user__email);对 DateTimeField 加密?更不可行——时间运算、索引、范围查询全部瘫痪。
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
替代思路:
- 敏感关联数据(如用户身份证绑定关系)改用独立加密表 + 随机token映射,主表只存token
- JSON中仅加密特定键(如
"id_card"),其余字段明文,用自定义JSON序列化器预处理 - 时间类敏感信息(如出生日期)可转为哈希+盐值存储(仅用于校验,不还原),或改用年龄区间等脱敏表达
迁移已有明文数据时,必须分两阶段滚动更新
线上表已有百万级明文数据,不能停服执行 ALTER TABLE ... MODIFY COLUMN。正确做法是新增加密字段(如 email_encrypted),写双写逻辑(新数据同时写明文+加密字段),再用后台任务批量迁移旧数据,最后删掉明文字段并重命名。
关键风险点:
- 迁移脚本必须带断点续传和失败重试,用
django.core.management.BaseCommand实现,避免OOM - 双写期间若加密失败,需记录日志并 fallback 到明文字段,保证业务可用
- admin、API、search等所有读取入口必须同步切换到加密字段,漏一处就会暴露明文
- 测试时用真实密钥跑一遍全流程,Fernet解密失败会抛
cryptography.fernet.InvalidToken,不是静默失败
最易被忽略的是密钥轮换——Fernet不支持密钥热替换。一旦密钥泄露或到期,必须重新加密全量数据,而这个过程没有原子性保障。生产环境务必提前设计密钥版本字段(如 encryption_key_version)和多密钥解密逻辑,否则某天运维改了个环境变量,整个用户邮箱就再也读不出来了。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










