在设计 Django Model 时,可能会遇到一些保存敏感字段的信息,比如密码、密钥等。
class TargetAuthInfo(models.Model):
title = models.CharField("标题", max_length=200, default="未命名")
address = models.CharField("地址", max_length=200, blank=True)
endpoint = models.CharField("Endpoint", max_length=200, blank=True)
username = models.CharField("用户名", max_length=200, blank=True)
password = EncryptedField("密码", max_length=200, blank=True)比如上面的 password 字段,需要保存节点的认证信息,如果明文保存的话,显然会存在严重的安全风险。
为了解决这个问题,可以使用加密算法对明文密码进行加密,通常加密算法还需要一个密钥,这个是解密数据的 Key,可以保存在环境变量或机器的某个位置,需要时读取。这样即便是数据库泄密,我们的敏感字段也不能被反解出来。
加密方式
在 Python 语言环境下,可以使用 cryptography 库。
from cryptography.fernet import Fernet
cipher = Fernet(FORNET_KEY)cipher 对象提供加、解密的接口,至于 FORNET_KEY 后面会说。
Django Model 定义
结合 Django 框架,可以自定义一个加密字段,封装加密器,重写 get 和 set 方法。
from cryptography.fernet import Fernet
class EncryptedField(models.CharField):
def __init__(self, *args, **kwargs):
self.cipher = Fernet(settings.FORNET_KEY)
super().__init__(*args, **kwargs)
def get_prep_value(self, value):
return self.cipher.encrypt(value.encode()).decode()
def from_db_value(self, value, expression, connection):
return self.cipher.decrypt(value.encode()).decode()使用
class TargetAuthInfo(models.Model):
title = models.CharField("标题", max_length=200, default="未命名")
address = models.CharField("地址", max_length=200, blank=True)
endpoint = models.CharField("Endpoint", max_length=200, blank=True)
username = models.CharField("用户名", max_length=200, blank=True)
password = EncryptedField("密码", max_length=200, blank=True) # 使用自定义加密字段生成 FORNET_KEY
前面说到,加密需要一个密钥,如果是使用 cryptography 的话,可以这样生成。
pip install cryptography
python
>>> from cryptography.fernet import Fernet
>>> key = Fernet.generate_key()
... print("Fernet Key:", key.decode())示例。
wii 🌐 work misthub-server main is 📦 v0.1.0 via 🐍 v3.10.13 ❯ poetry run pip install cryptography
The currently activated Python version 3.10.13 is not supported by the project (>=3.12).
Trying to find and use a compatible version.
Using python3.13 (3.13.3)
Creating virtualenv misthub-server-qK9S8n11-py3.13 in /home/wii/.cache/pypoetry/virtualenvs
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Collecting cryptography
Downloading https://pypi.tuna.tsinghua.edu.cn/packages/89/6b/09c30543bb93401f6f88fce556b3bdbb21e55ae14912c04b7bf355f5f96c/cryptography-46.0.1-cp311-abi3
-manylinux_2_34_x86_64.whl (4.6 MB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.6/4.6 MB 19.3 MB/s eta 0:00:00
Collecting cffi>=2.0.0 (from cryptography)
Downloading https://pypi.tuna.tsinghua.edu.cn/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylin
ux2014_x86_64.manylinux_2_17_x86_64.whl (219 kB)
Collecting pycparser (from cffi>=2.0.0->cryptography)
Downloading https://pypi.tuna.tsinghua.edu.cn/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.wh
l (118 kB)
Installing collected packages: pycparser, cffi, cryptography
Successfully installed cffi-2.0.0 cryptography-46.0.1 pycparser-2.23
[notice] A new release of pip is available: 25.1.1 -> 25.2
[notice] To update, run: pip install --upgrade pip
wii 🌐 work misthub-server main is 📦 v0.1.0 via 🐍 v3.10.13 ❯ poetry run python 4s
The currently activated Python version 3.10.13 is not supported by the project (>=3.12).
Trying to find and use a compatible version.
Using python3.13 (3.13.3)
Python 3.13.3 (main, May 7 2025, 08:28:05) [GCC 13.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from cryptography.fernet import Fernet
>>> key = Fernet.generate_key()
... print("Fernet Key:", key.decode())
...
Fernet Key: u6C-TkZtfPnxdKFzU6AYX-Wjp5kI-m6GDzXI10hO5u8=
>>> 这个 key 可放在项目的 settings 里面,新增一个 FORNET_KEY 字段。
FORNET_KEY='u6C-TkZtfPnxdKFzU6AYX-Wjp5kI-m6GDzXI10hO5u8='