Django中AESSIV加密数据解密异常:无法还原明文问题排查
无法解密数据库中加密数据的问题排查与解决
核心问题原因
问题出在加密后的数据类型处理不当:
encrypt_field函数返回的是base64.b64encode()的结果,这是一个bytes对象。存入Django的CharField时,Django会自动将其转换为字符串表示,也就是类似"b'CSPex4eChMQ...'"的格式(包含b'前缀和'后缀)。- 解密时,
input_text是这个带b''包裹的字符串,调用base64.b64decode()会因非法字符(b'和')抛出异常,导致decrypt_field直接返回原输入字符串,也就是你看到的错误结果。
解决方案
方案1:加密时返回Base64字符串(推荐,适配CharField/TextField)
修改encrypt_field函数,将Base64编码后的bytes转换为UTF-8字符串,确保存入数据库的是纯Base64文本,无多余的b''包裹:
def encrypt_field(input_text): try: if isinstance(input_text, str): input_text = input_text.encode() enc_text = cipher_suite.encrypt(input_text, associated_data = None) enc_text_base_64 = base64.b64encode(enc_text) # 将bytes转换为字符串后返回 return enc_text_base_64.decode('utf-8') except Exception as e: error_logger.error(f"exception in encrypt field {str(e)} on field {input_text}") return input_text
修改后存入数据库的是纯Base64字符串,解密时input_text为正常字符串,base64.b64decode()可正确解析,最终返回明文。
方案2:使用BinaryField存储原始加密字节
若坚持用BinaryField存储,需调整加密解密流程,跳过Base64编码(BinaryField直接存储bytes):
修改加密函数
def encrypt_field(input_text): try: if isinstance(input_text, str): input_text = input_text.encode() # 直接返回加密后的bytes,跳过Base64编码 return cipher_suite.encrypt(input_text, associated_data = None) except Exception as e: error_logger.error(f"exception in encrypt field {str(e)} on field {input_text}") return input_text
修改解密函数
def decrypt_field(input_text): try: # BinaryField读取的是bytes,直接解密 decrypted_field = cipher_suite.decrypt(input_text, associated_data = None) return decrypted_field.decode('utf-8') except Exception as e: print(e) error_logger.error(f"exception in decrypt_field {e} on field {input_text}") return input_text
同步修改Model字段
class User(AbstractUser): username = models.BinaryField(unique=True) email = models.BinaryField(unique=True) # 其他字段保持不变...
额外验证步骤
- 清理数据库中已有的错误格式数据(带
b''的字符串),重新加密存入。 - 单独测试加密解密流程:调用
encrypt_field("redgrave@example.com")确认返回纯字符串,再传入decrypt_field验证是否能得到原明文。
内容的提问来源于stack exchange,提问作者Redgrave
相关产品推荐
相关产品推荐

