演进历程概述
阶段 | 技术 | 安全性 | 特点 |
---|---|---|---|
第1代 | 明文存储 | ⚠️ 极低 | 密码直接可见 |
第2代 | SHA256哈希 | 🟡 低 | 单向加密,但相同密码哈希相同 |
第3代 | bcrypt加盐哈希 | 🟢 高 | 自动加盐,抗暴力破解 |
第1代:明文存储(绝对不要使用!)
代码实现
def add_user_plaintext(username, password):
"""明文存储 - 极其危险!"""
with open(USER_FILE, 'a') as f:
f.write(f'{username}:{password}\n')
def verify_user_plaintext(username, password):
"""明文验证"""
with open(USER_FILE, 'r') as f:
for line in f:
if line.startswith(username + ':'):
stored_password = line.split(':')[1].strip()
return stored_password == password
return False
存储格式
张三:123456
张四:password123
安全问题
-
✅ 数据库泄露即密码泄露
-
✅ 管理员可直接查看用户密码
-
✅ 无任何安全防护
第2代:SHA256哈希存储
代码实现
import hashlib
def add_user_sha256(username, password):
"""SHA256哈希存储 - 基本防护"""
hashed_password = hashlib.sha256(password.encode()).hexdigest()
with open(USER_FILE, 'a') as f:
f.write(f'{username}:{hashed_password}\n')
def verify_user_sha256(username, password):
"""SHA256验证"""
hashed_input = hashlib.sha256(password.encode()).hexdigest()
with open(USER_FILE, 'r') as f:
for line in f:
if line.startswith(username + ':'):
stored_hash = line.split(':')[1].strip()
return stored_hash == hashed_input
return False
存储格式
密码一致时,哈希值一样,例如 密码 123456 哈希值如下。
王五:8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92
王六:8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92
安全改进
-
✅ 密码不可直接查看
-
✅ 单向加密,无法反向解密
-
❌ 相同密码哈希值相同
-
❌ 易受彩虹表攻击
第3代:bcrypt加盐哈希(现代标准)
安装依赖
pip install bcrypt
代码实现
import bcrypt
def add_user_bcrypt(username, password):
"""bcrypt加盐哈希 - 现代安全标准"""
# 自动生成盐值并哈希(盐值包含在哈希结果中)
hashed_password = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
with open(USER_FILE, 'a') as f:
f.write(f'{username}:{hashed_password.decode()}\n')
def verify_user_bcrypt(username, password):
"""bcrypt验证"""
with open(USER_FILE, 'r') as f:
for line in f:
if line.startswith(username + ':'):
stored_hash = line.split(':')[1].strip()
# bcrypt自动从存储的哈希值中提取盐值
return bcrypt.checkpw(password.encode(), stored_hash.encode())
return False
存储格式
密码相同 同为:123456 但是哈希值不同 会自动随机加盐值。
李大:$2b$12$04QFaLgTUQ5ZJRU9oLzwueOLhVhhN0m1FcFXVjiI/urTx7PKPuizW
李二:$2b$12$e6HOGej8UZGGawqlECgQaedO9YhseKweKNYWh6aAdyjJXXA5XzfFq
解析说明:
$2b$12$04QFaLgTUQ5ZJRU9oLzwueOLhVhhN0m1FcFXVjiI/urTx7PKPuizW
$2b$ #算法版本标识符
12$ #计算成本参数(12轮)
04QFaLgTUQ5ZJRU9oLzwue # 22字符的盐值(自动生成)
OLhVhhN0m1FcFXVjiI/urTx7PKPuizW # 31字符的哈希结果
安全特性
-
✅ 每个密码有唯一盐值
-
✅ 相同密码产生不同哈希值
-
✅ 可调节计算成本(抗暴力破解)
-
✅ 专门为密码设计(抗GPU/ASIC攻击)
-
✅ 自动盐值管理
完整演进示例
# 选择使用的密码存储方式
PASSWORD_METHOD = 'bcrypt' # 可选: 'plaintext', 'sha256', 'bcrypt'
def add_user(username, password):
"""根据配置选择密码存储方式"""
if PASSWORD_METHOD == 'plaintext':
add_user_plaintext(username, password)
elif PASSWORD_METHOD == 'sha256':
add_user_sha256(username, password)
else: # bcrypt
add_user_bcrypt(username, password)
def verify_user(username, password):
"""根据配置选择密码验证方式"""
if PASSWORD_METHOD == 'plaintext':
return verify_user_plaintext(username, password)
elif PASSWORD_METHOD == 'sha256':
return verify_user_sha256(username, password)
else: # bcrypt
return verify_user_bcrypt(username, password)
安全对比表
攻击方式 | plaintext(明文) | SHA256 | bcrypt |
---|---|---|---|
数据库泄露 | 🔴 完全暴露 | 🟡 哈希暴露 | 🟢 相对安全 |
彩虹表攻击 | 🔴 直接可用 | 🟡 有效 | 🟢 无效 |
相同密码识别 | 🔴 直接可见 | 🟡 哈希相同 | 🟢 哈希不同 |
暴力破解 | 🔴 极易 | 🟡 容易 | 🟢 困难 |
GPU加速破解 | 🔴 极快 | 🟡 很快 | 🟢 很慢 |
最佳实践
-
始终使用bcrypt或其他专门密码哈希算法(如Argon2)
-
设置适当的计算成本(12-14是常用值)
-
定期要求用户更改密码
-
实施多因素认证
-
监控异常登录行为
现代Web应用应该直接从第3代(bcrypt)开始,避免使用前两代不安全的技术。