如何在Django中对整数字段实现加密/令牌化处理保障数据安全
Django 保密整数字段实现方案
你示例中Django原生密码字段的核心逻辑是不可逆哈希:使用set_password时自动对明文做哈希处理后存储,authenticate时将输入值做相同哈希后和存储值比对,全程无法从存储的密文还原出原始明文,仅支持匹配校验。
如果你的需求是「仅校验数值是否匹配、不需要给用户展示明文」,可以直接复用Django的密码哈希逻辑,实现和密码字段完全一致的效果;如果需要支持所属用户查看明文,就要改用对称加密方案实现,具体方案如下:
方案1:无需还原明文(和原生密码字段逻辑完全一致)
直接复用Django内置的密码哈希工具即可:
from django.db import models from django.contrib.auth.hashers import make_password, check_password from django.contrib.auth.models import User class UserSecret(models.Model): owner = models.OneToOneField(User, on_delete=models.CASCADE) # 存储哈希后的整数值,底层用CharField即可 secret_num_hash = models.CharField(max_length=256) # 类似set_password的设值方法 def set_secret_num(self, raw_num: int): self.secret_num_hash = make_password(str(raw_num)) # 类似authenticate的校验方法 def check_secret_num(self, input_num: int) -> bool: return check_password(str(input_num), self.secret_num_hash)
调用方式和你示例的密码操作完全一致:
# 存值 obj = UserSecret.objects.create(owner=request.user) obj.set_secret_num(123456) obj.save() # 校验 is_match = obj.check_secret_num(123456) # 返回True
该方案下存储的是不可逆哈希值,就算是管理员也无法从密文还原出原始整数值。
方案2:需要支持所属用户查看明文(对称加密实现)
该方案采用对称加密算法,存储时加密为密文,有权限的用户可以解密查看明文:
第一步:定义自定义加密整数字段
from django.db import models from django.core import signing from django.core.exceptions import ValidationError class EncryptedIntegerField(models.Field): description = "对称加密存储的整数字段" def from_db_value(self, value, expression, connection): if value is None: return value try: # 自动解密数据库读取的密文 return signing.loads(value) except signing.BadSignature: raise ValidationError("加密数据已被篡改") def to_python(self, value): if isinstance(value, int) or value is None: return value try: return signing.loads(value) except signing.BadSignature: raise ValidationError("加密数据已被篡改") def get_prep_value(self, value): if value is None: return value # 写入数据库前自动加密 return signing.dumps(value) def get_internal_type(self): # 加密后为字符串,底层用TextField存储 return "TextField"
第二步:模型中使用并加权限控制
from django.db import models from django.contrib.auth.models import User from .fields import EncryptedIntegerField class UserSecret(models.Model): owner = models.OneToOneField(User, on_delete=models.CASCADE) secret_num = EncryptedIntegerField() # 仅所属用户可获取明文 def get_secret_num(self, request_user: User) -> int | None: if request_user == self.owner: return self.secret_num return None
第三步:Admin后台隐藏字段
配置admin.py避免管理员看到加密后的内容:
from django.contrib import admin from .models import UserSecret @admin.register(UserSecret) class UserSecretAdmin(admin.ModelAdmin): list_display = ('owner',) exclude = ('secret_num',)
注意事项
- 方案1的不可逆哈希安全性更高,不需要还原明文时优先选择该方案
- 方案2的加密密钥默认使用Django配置的
SECRET_KEY,生产环境务必保证该值不泄露,泄露后所有加密数据可被破解 - 生产环境建议优先使用
django-fernet-fields等成熟第三方加密字段库,避免自行实现的加密逻辑有安全漏洞
内容的提问来源于stack exchange,提问作者Ali Husham
相关产品推荐
相关产品推荐

