字段加密基础知识

说到字段加密,很多人第一反应就是「用 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())
小提示:对称加密的密钥一定要单独保管,别和数据库放在同一台机器上。我之前见过密钥就写在 settings.py 里的,那跟没加密没啥区别。

非对称加密:安全但慢

非对称加密用的是一对钥匙——公钥和私钥。公钥可以公开,私钥自己藏好。别人用公钥加密数据,只有你能用私钥解开。反过来,你用私钥签名,别人用公钥验证身份。

这解决了对称加密的密钥分发难题。但代价是速度慢,比对称加密慢几百倍。所以它不适合加密大字段,一般只用来加密小数据,比如 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)
)
注意:非对称加密的密钥长度不要低于 2048 位。1024 位的 RSA 现在已经能被暴力破解了,我曾经在遗留系统里见过,果断让业务方升级。

哈希算法:不可逆的「指纹」

哈希跟加密不一样。加密是可逆的,哈希是不可逆的。你把一段数据扔进哈希函数,出来一个固定长度的摘要。你没办法从摘要反推出原文。这玩意不是用来「加密数据」的,而是用来「验证完整性」或「存储密码」的。

常见的哈希算法有 SHA-256、SHA-3、SM3。MD5 和 SHA-1 已经被证明不安全,别再用了。我记得有一次做代码审计,发现系统还用 MD5 存管理员密码……我当时就出了一身冷汗。

import hashlib

password = b"my_secret_password"
digest = hashlib.sha256(password).hexdigest()
print(digest)  # 输出固定64位十六进制字符串
关键认知:哈希不是加密!哈希不是加密!哈希不是加密!重要的事情说三遍。哈希是单向摘要,它不能用来「解密」。如果有人跟你说「MD5 加密密码」,直接纠正他。

加盐:让哈希更安全

直接用哈希存密码有个大问题——同样的密码会得到同样的摘要。攻击者可以提前算好一本「彩虹表」,里面存了常见密码的哈希值,一比对就能还原你的密码。

加盐就是在密码后面拼接一段随机字符串,然后再做哈希。每个用户的盐不一样,所以就算密码相同,存到数据库里的哈希值也不一样。彩虹表直接废掉。

我以前踩过一个坑:自己手写加盐逻辑,盐的长度不够,只有 4 位。后来发现同一批用户的盐居然有重复的……从那以后我再也不自己写盐了,直接用现成的库。

import bcrypt

# 加盐哈希(盐自动生成并嵌入结果中)
hashed = bcrypt.hashpw(b"my_password", bcrypt.gensalt())
print(hashed)

# 验证密码
if bcrypt.checkpw(b"my_password", hashed):
    print("密码正确")
建议:直接用 bcrypt、scrypt 或 Argon2,别自己拼盐。这些库把盐的生成、拼接、哈希、迭代都封装好了,你只管调用就行。我所有项目现在统一用 bcrypt,省心。

四种技术怎么选

好,四种技术都过了一遍。那实际项目里到底用哪个?我整理了一张对比表,你存下来当参考。

特性 对称加密 非对称加密 哈希算法 加盐哈希
可逆性 可逆 可逆 不可逆 不可逆
密钥数量 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,加盐迭代一步到位。

下面这张图把这四种技术的核心逻辑和关系串起来了,你一看就明白。

字段加密技术全景图 对称加密 非对称加密 哈希算法 加盐哈希 密钥相同 速度快,适合大批量 AES-256-GCM / SM4 密钥不同 安全性高,速度慢 RSA-2048 / ECC / SM2 不可逆 固定长度,防篡改 SHA-256 / SHA-3 / SM3 加随机盐 防彩虹表攻击 bcrypt / scrypt / Argon2 实际项目中的组合用法 传输密钥 → 非对称加密 | 存储数据 → 对称加密 | 密码验证 → 哈希 + 盐

这四种技术是后续所有 ORM 加密改造的基石。你在选择方案时,不用纠结「哪个最好」,而是问自己「我需要可逆还是不可逆」「我加密的是数据还是密码」。想清楚这两点,方案自然就浮出来了。