#密码安全加密:使用 Werkzeug 进行加盐哈希存储
📂 所属阶段:第三阶段 — 用户系统(安全篇)
🔗 相关章节:Flask-Login 实战 · 数据验证
#1. 绝对禁止的做法
# ❌ 明文存储(灾难!)
user.password = request.form["password"]
# ❌ 简单哈希(MD5/SHA1 可被彩虹表秒破)
import hashlib
hashed = hashlib.md5(password.encode()).hexdigest()
# ❌ 固定盐值(所有用户同一个盐)
salt = "myapp_salt"
hashed = hashlib.sha256((password + salt).encode()).hexdigest()正确做法:慢哈希 + 随机盐 + Werkzeug
#2. Werkzeug 哈希工具
#2.1 核心函数
from werkzeug.security import generate_password_hash, check_password_hash
# 生成哈希
password_hash = generate_password_hash("MyPassword123!")
# 结果示例:pbkdf2:sha256:600000$salt$hash...
# 验证密码
is_correct = check_password_hash(password_hash, "MyPassword123!")
print(is_correct) # True#2.2 生成安全哈希
# 注册用户时
def create_user(email, password):
user = User(
email=email,
# 生成带随机盐的安全哈希
password_hash=generate_password_hash(password),
)
db.session.add(user)
db.session.commit()
# 登录验证时
def authenticate_user(email, password):
user = User.query.filter_by(email=email).first()
if user and check_password_hash(user.password_hash, password):
return user
return None#2.3 哈希算法说明
# Werkzeug 默认使用 pbkdf2:sha256
# 格式:pbkdf2:sha256:迭代次数$盐$哈希
# 可选算法:
generate_password_hash("password", method="pbkdf2:sha256")
generate_password_hash("password", method="scrypt") # 更安全,但慢
generate_password_hash("password", method="bcrypt") # 需要 pip install bcrypt#3. 完整用户模型
# app/models/user.py
from datetime import datetime
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
from app.extensions import db
class User(UserMixin, db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(50), unique=True)
email = db.Column(db.String(120), unique=True, nullable=False)
password_hash = db.Column(db.String(256), nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
# 密码由 User 类管理,不作为独立字段暴露
@property
def password(self):
raise AttributeError("密码不可读!")
@password.setter
def password(self, plaintext):
"""设置密码时自动哈希"""
self.password_hash = generate_password_hash(plaintext)
# 验证密码
def check_password(self, plaintext):
return check_password_hash(self.password_hash, plaintext)
def __repr__(self):
return f"<User {self.email}>"#4. 安全最佳实践清单
✅ 推荐
1. 始终使用 Werkzeug 的 generate_password_hash
2. 不要存储明文密码
3. 不要在日志中记录密码
4. 密码验证失败时,不要告诉用户是"密码错"还是"用户不存在"(防止枚举攻击)
5. 生产环境使用 HTTPS 传输密码
6. 使用 `method="bcrypt"` 或 `method="scrypt"`(更强安全)
❌ 避免
1. 明文存储密码
2. 用 MD5/SHA1 做密码哈希
3. 使用固定盐值
4. 密码明文出现在错误信息中#5. 小结
from werkzeug.security import generate_password_hash, check_password_hash
# 注册时:生成哈希
password_hash = generate_password_hash(password)
# 登录时:验证
if check_password_hash(user.password_hash, password):
# 登录成功💡 记住:密码哈希是 Web 应用的安全底线。永远不要心存侥幸明文存储,Werkzeug 让这一切变得简单。
🔗 扩展阅读

