字段加密基础知识
说到字段加密,很多人第一反应就是「用 AES 就行了呗」。嗯,真这么简单就好了。我在工作中接过不少数据泄露的复盘,十次里有八次都是加密方案没选对,或者选了算法但用错了场景。你想想,数据库里存的是用户手机号、身份证、甚至支付密码——这些东西一旦裸奔,后果谁都兜不住。
所以今天咱们先把四种最基础的技术吃透。对称加密、非对称加密、哈希算法、加盐。别看名字多,核心逻辑其实就那么几条线。我习惯把它们分成两类:「可逆的」和「不可逆的」。前者用来加密数据,后者用来验证身份。下面一个一个说。
对称加密:又快又简单
对称加密的核心就一句话:加密和解密用同一把钥匙。你想想,就像你家里的大门,锁门用这把钥匙,开门还用这把钥匙。
优点很明显——速度快。适合加密大批量数据,比如整张表的手机号字段。缺点是密钥怎么安全地交给对方?我以前在第一个电商项目里,就是直接用对称加密加密用户地址,结果密钥硬编码在配置文件里……后来被安全审计骂得不轻。
常见的对称算法有 AES(尤其是 AES-256-GCM)、SM4(国密标准)。我个人习惯用 AES-256-GCM,因为它自带认证标签,能防篡改。
from cryptography.fernet import Fernet
# 生成密钥
key = Fernet.generate_key()
cipher = Fernet(key)
# 加密
encrypted = cipher.encrypt(b"13800138000")
print(encrypted)
# 解密
decrypted = cipher.decrypt(encrypted)
print(decrypted.decode())
非对称加密:安全但慢
非对称加密用的是一对钥匙——公钥和私钥。公钥可以公开,私钥自己藏好。别人用公钥加密数据,只有你能用私钥解开。反过来,你用私钥签名,别人用公钥验证身份。
这解决了对称加密的密钥分发难题。但代价是速度慢,比对称加密慢几百倍。所以它不适合加密大字段,一般只用来加密小数据,比如 AES 密钥本身,或者做数字签名。
我在项目中遇到过最典型的用法是「混合加密」:用非对称加密传输对称密钥,再用对称密钥加密业务数据。既安全又快,两全其美。
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import serialization, hashes
# 生成密钥对
private_key = rsa.generate_private_key(
public_exponent=65537, key_size=2048
)
public_key = private_key.public_key()
# 公钥加密
message = b"加密的手机号"
ciphertext = public_key.encrypt(
message,
padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(), label=None)
)
# 私钥解密
plaintext = private_key.decrypt(
ciphertext,
padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(), label=None)
)
哈希算法:不可逆的「指纹」
哈希跟加密不一样。加密是可逆的,哈希是不可逆的。你把一段数据扔进哈希函数,出来一个固定长度的摘要。你没办法从摘要反推出原文。这玩意不是用来「加密数据」的,而是用来「验证完整性」或「存储密码」的。
常见的哈希算法有 SHA-256、SHA-3、SM3。MD5 和 SHA-1 已经被证明不安全,别再用了。我记得有一次做代码审计,发现系统还用 MD5 存管理员密码……我当时就出了一身冷汗。
import hashlib
password = b"my_secret_password"
digest = hashlib.sha256(password).hexdigest()
print(digest) # 输出固定64位十六进制字符串
加盐:让哈希更安全
直接用哈希存密码有个大问题——同样的密码会得到同样的摘要。攻击者可以提前算好一本「彩虹表」,里面存了常见密码的哈希值,一比对就能还原你的密码。
加盐就是在密码后面拼接一段随机字符串,然后再做哈希。每个用户的盐不一样,所以就算密码相同,存到数据库里的哈希值也不一样。彩虹表直接废掉。
我以前踩过一个坑:自己手写加盐逻辑,盐的长度不够,只有 4 位。后来发现同一批用户的盐居然有重复的……从那以后我再也不自己写盐了,直接用现成的库。
import bcrypt
# 加盐哈希(盐自动生成并嵌入结果中)
hashed = bcrypt.hashpw(b"my_password", bcrypt.gensalt())
print(hashed)
# 验证密码
if bcrypt.checkpw(b"my_password", hashed):
print("密码正确")
四种技术怎么选
好,四种技术都过了一遍。那实际项目里到底用哪个?我整理了一张对比表,你存下来当参考。
| 特性 | 对称加密 | 非对称加密 | 哈希算法 | 加盐哈希 |
|---|---|---|---|---|
| 可逆性 | 可逆 | 可逆 | 不可逆 | 不可逆 |
| 密钥数量 | 1 个 | 2 个(公钥+私钥) | 无 | 1 个(盐值) |
| 速度 | 快 | 慢 | 快 | 中等(可调迭代) |
| 典型算法 | AES-256-GCM, SM4 | RSA-2048, ECC, SM2 | SHA-256, SHA-3, SM3 | bcrypt, scrypt, Argon2 |
| 适用场景 | 存储加密(手机号、地址) | 密钥交换、数字签名 | 数据完整性校验 | 密码存储 |
简单总结一下我的选型原则:
- 要存身份证、手机号这类敏感信息?用 AES-256-GCM 对称加密。
- 要在两个系统之间安全传密钥?用 RSA 或 ECC 非对称加密。
- 要校验文件或消息有没有被改过?用 SHA-256 哈希。
- 要存用户密码?直接用 bcrypt 或 Argon2,加盐迭代一步到位。
下面这张图把这四种技术的核心逻辑和关系串起来了,你一看就明白。
这四种技术是后续所有 ORM 加密改造的基石。你在选择方案时,不用纠结「哪个最好」,而是问自己「我需要可逆还是不可逆」「我加密的是数据还是密码」。想清楚这两点,方案自然就浮出来了。