mysql中aes_encrypt返回blob导致乱码,需用to_base64()存储、from_base64()还原后解密;密钥长度必须为16/24/32字节,否则静默返回null;推荐使用确定性哈希辅助查询,避免加密字段直接where。

MySQL 中用 AES_ENCRYPT 存敏感字段,但查出来是乱码?
不是加密失败,是默认返回 BLOB 类型,直接 SELECT 会显示十六进制或乱码。必须显式转成可读格式,比如用 HEX() 或 TO_BASE64() 存,对应用 UNHEX() / FROM_BASE64() 解。
- 存的时候别直接
INSERT INTO user (pwd) VALUES (AES_ENCRYPT('123', 'key')),而要写成INSERT INTO user (pwd) VALUES (TO_BASE64(AES_ENCRYPT('123', 'key'))) - 查的时候得先还原再解密:
SELECT AES_DECRYPT(FROM_BASE64(pwd), 'key') FROM user - 密钥长度必须是 128/192/256 位(即 16/24/32 字节),传错长度会静默失败,返回
NULL—— 这是最常踩的坑 -
AES_ENCRYPT默认用 AES-128-CBC,不带 IV;如果需要更安全的随机 IV,得自己生成并拼接存储,MySQL 原生不支持自动管理 IV
PostgreSQL 里 pgcrypto 的 encrypt() 总报 “wrong key length”
因为 encrypt() 要求密钥必须是二进制字节流,不是字符串。你传 'mykey',它按 UTF8 算长度是 5 字节,但 AES-128 要 16 字节,直接报错。
- 正确做法是用
convert_to('mykey', 'utf8')+md5()截取,或者更稳妥地用digest('mykey', 'sha256')得到 32 字节密钥 - 加密函数推荐用
pgp_sym_encrypt(),它自动处理密钥派生、IV、填充和 Base64 编码,存出来就是可读字符串,不用手动转码 -
pgp_sym_encrypt('data', 'key', 'cipher-algo=aes256')比裸用encrypt()更适合业务场景,但注意它依赖pgcrypto扩展已启用
SQLite 没内置加密函数,真要加怎么办?
官方 SQLite 不支持透明加密,sqlite3 命令行工具也无 AES_ENCRYPT。所谓“加密 SQLite”基本靠三类方案:应用层手动加解密、第三方扩展(如 SQLCipher)、或文件系统级加密。
该系统采用VS2005+SQL2000+Extjs2.0开发由于学extjs 一月不到 属初学者,项目有很多不足地方请见谅(注释不标准按自己想法随意注释了一下)数据库脚本:压缩包目录下.DB.sql便是该项目为双用户:管理员 与营业员 角色登陆显示不同信息数据库方面一小部分功能运用存储过程或者直接附加DB_51aspx下Sql数据库文件
- 别在 SQL 里写
ENCRYPT(data, key)—— 这语法根本不存在,会报no such function: ENCRYPT - SQLCipher 是最常用选择,但它是独立编译版本,普通
pip install pysqlite3不带它;要用就得装sqlcipher3包,并用PRAGMA key = 'x'xx'开启 - 如果只是临时保护配置字段,建议在应用代码里用 Python 的
cryptography库做 AES-GCM 加密,存进 TEXT 字段,比折腾数据库扩展更可控
加密后 WHERE 查询变慢,甚至没法走索引?
对加密字段做 WHERE encrypted_col = AES_ENCRYPT(?, ?) 看似合理,实际等于每次查询都重新加密一次,还无法利用索引 —— 因为加密结果依赖 IV 或随机盐,相同明文加密后值不同。
- 想按加密字段查,唯一靠谱方式是确定性加密(如 AES-SIV 或 HMAC+AES),但主流数据库都不原生支持;MySQL 8.4+ 的
AES_ENCRYPT加MODE=ECB虽然确定性,但 ECB 极不安全,别用 - 常见折中:把关键查询字段(如手机号)额外存一个加盐哈希(
SHA2(CONCAT(phone, salt))),用于等值查找,加密字段只存完整敏感内容 - 记住:加密不是索引友好操作。一旦字段加密了,就默认它只能做「取出来再解密后处理」,别指望在数据库里高效过滤
密钥轮换、字段粒度控制、加密与业务逻辑耦合程度——这些才是上线后真正卡住手脚的地方,比选哪个函数难得多。









