Flask与SQLAlchemy场景下如何加密长用户输入避免数据库明文可见
最优实现方案
核心选型逻辑
要满足你无法直接从数据库读取用户私密日记的需求,核心原则是加密密钥不与密文同库存储,针对Flask+SQLAlchemy技术栈,下面按安全等级从高到低给出两种可直接落地的方案:
方案1:端到端加密(最高安全等级,完全无法查看用户内容)
这是最契合需求的方案,加解密全在用户侧完成,服务端仅存储密文,你作为管理员完全没有解密能力。
- 实现逻辑:
- 用户注册时,引导用户设置独立的日记加密密码(可与登录密码分开,降低撞库风险),前端通过
AES-256-GCM算法派生加密密钥,密钥永远不发送到服务端 - 用户保存日记时,前端先将明文内容用密钥加密为密文,再传给Flask后端存入数据库
- 用户查看日记时,后端仅返回密文给前端,前端用本地存储的密钥解密为明文展示
- 用户注册时,引导用户设置独立的日记加密密码(可与登录密码分开,降低撞库风险),前端通过
- 注意点:该方案下用户忘记加密密码则内容永久无法找回,管理员也无权恢复,适合主打绝对隐私的产品定位。
方案2:SQLAlchemy字段级加密(平衡安全与易用,直接查数据库看不到明文)
如果不想让用户承担密码丢失的风险,又要满足直接查数据库看不到明文的要求,可以用自定义字段类型实现透明加密,密钥单独存储在环境变量中,不写入数据库。
实现步骤
- 安装依赖
pip install cryptography python-dotenv - 自定义加密字段类型
from cryptography.fernet import Fernet from sqlalchemy import TypeDecorator, Text from flask import current_app class EncryptedText(TypeDecorator): impl = Text cache_ok = True # 写入数据库前加密 def process_bind_param(self, value, dialect): if not value: return value fernet = Fernet(current_app.config['ENCRYPTION_KEY'].encode()) return fernet.encrypt(value.encode()).decode() # 从数据库读取后解密 def process_result_value(self, value, dialect): if not value: return value fernet = Fernet(current_app.config['ENCRYPTION_KEY'].encode()) return fernet.decrypt(value.encode()).decode()
- 配置加密密钥
先执行python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"生成密钥,写入项目根目录的.env文件,不要提交到代码仓库,也不要存入数据库:
# Flask 配置文件 import os from dotenv import load_dotenv load_dotenv() ENCRYPTION_KEY = os.getenv('ENCRYPTION_KEY')
- 模型中直接使用加密字段
from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() class Diary(db.Model): id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) # 用自定义的EncryptedText替代普通Text类型即可 content = db.Column(EncryptedText, nullable=False) create_time = db.Column(db.DateTime, default=db.func.now())
- 该方案对业务代码侵入极小,直接查询数据库拿到的是无意义的加密字符串,只有通过Flask应用走正常业务逻辑才能解密拿到明文。只要将密钥与数据库分开存储(比如数据库存云服务器,密钥存在独立的密钥管理服务),就算数据库被拖库也不会泄露用户隐私。
- 注意点:不要在业务日志中打印日记明文,定期轮换加密密钥即可。
避坑提示
- 不要自行实现加密算法,直接使用成熟的
cryptography库官方实现即可 - 若有日记标题、地理位置等其他敏感字段,也可以同步用加密字段存储
内容的提问来源于stack exchange,提问作者Hector Astrom
相关产品推荐
相关产品推荐

