一个关键结论:数据库加密虽然无法阻止 SQL 注入攻击本身,但能有效防止数据被拖库后直接暴露明文。SQL 注入与数据加密属于两个完全不同的安全层面。
SQL注入与数据库加密:两个独立的安全维度
SQL 注入源于输入验证和查询构造的缺陷,攻击者可以篡改执行逻辑;而 AES 加密则是对静态存储的数据提供机密性保护。即使攻击者利用 UNION SELECT 或报错注入技术将整张表拖出,得到的也仅仅是密文——没有密钥,就无法还原身份证号、手机号等原始敏感信息。
- SQL 注入漏洞仍然存在,攻击者依然可以绕过认证,甚至执行删除数据库的操作
- 但“拖库即失守”的连锁反应被有效阻断:密文无法直接用于反诈骗、撞库攻击或社会工程学攻击
- 当你执行
SELECT encrypted_id_card FROM users WHERE id = 123查询时,返回的是乱码而非真实身份证号码
为什么必须使用AES-256-GCM,而不推荐直接调用AES_ENCRYPT()?
MySQL 的 AES_ENCRYPT() 函数在 5.7 版本中默认采用 ECB 模式,相同明文始终生成相同的密文,这相当于为攻击者提供了一份字典映射。虽然 8.0 以上版本支持 GCM 模式,但必须显式传入 iv(初始化向量)和 aad(附加认证数据),并且应用层需要自行校验 auth_tag——否则攻击者可能篡改密文,触发填充预言攻击。
- 在 ECB 模式下,如果两个用户填写相同的手机号,数据库中密文完全一致,直接暴露了数据的重复模式
- 当
AES_ENCRYPT(data, key)不传入 IV 参数时,MySQL 内部可能复用固定的 IV,效果等同于 ECB 模式 - GCM 模式要求每次加密都使用新的随机
iv,并需要将其存储;解密时必须原样传回,缺少任何一项都会导致失败
加密后如何实现按手机号查询?
不能直接使用 WHERE encrypted_phone = ? 进行查询,因为每次加密的结果不同。若需支持查询,就必须额外设计辅助机制:
- 对手机号计算
HMAC-SHA256(phone, salt_from_kms),存入phone_hash字段并建立索引;查询时使用同样的哈希值进行比对 - 使用确定性加密(如 AES-SIV),但这种方式会暴露“哪些记录的手机号相同”,对隐私有一定折损
- 如果想要完全不泄露任何模式?目前尚无成熟的方案能够支持高并发场景下的可搜索加密(Searchable Encryption)
最容易被忽略的一点是:密钥的保管比算法选择更为关键。即使采用了 AES-256-GCM,如果密钥被硬编码在代码里、存储在数据库同一实例中、或者通过环境变量明文暴露,那就像锁了门却把钥匙焊在门把手上——毫无安全性可言。
