mysql无真正加密函数,仅有单向哈希(如md5、sha1)和aes加解密;密码应由应用层用bcrypt等处理,aes需严格匹配模式、密钥、iv且密钥须为二进制。

MySQL 里没有真正意义上的「加密函数」,只有单向哈希函数
很多人在 SELECT 里用 ENCRYPT()、MD5() 或 SHA1() 时,以为是在「加密」,其实这些全是不可逆的哈希——你无法从结果反推出原始密码。MySQL 原生不提供 AES 加密/解密以外的双向加解密能力(且 AES_ENCRYPT() 要求密钥长度严格匹配,否则返回 NULL)。
常见误用场景:
- 用
MD5('password')存用户密码 → 一旦哈希被撞库或彩虹表破解,等同于明文泄露 - 试图用
ENCRYPT()(仅 Linux crypt() 支持)做跨平台存储 → Windows 下直接失效 - 调用
AES_DECRYPT()但没传对iv或密钥编码格式(比如用 UTF-8 字符串当二进制密钥)→ 返回NULL不报错,极难排查
AES_ENCRYPT / AES_DECRYPT 的正确用法和陷阱
这是 MySQL 中唯一可用的对称加解密函数族,但极易出错。关键不是“能不能用”,而是“怎么用才不会丢数据”。
51shop 由 PHP 语言开发, 使用快速的 MySQL 数据库保存数据 ,为中小型网站实现网上电子商务提供一个完美的解决方案.一、用户模块1. 用户注册:用户信息包括:用户ID、用户名、用户密码、性别、邮箱、省份、城市、 联系电话等信息,用户注册后不能立即使用,需由管理员激活账号,才可使用(此功能管理员可设置)2. 登录功能3. 资料修改:用户可修改除账号以后的所有资料4. 忘记密码:要求用
-
AES_ENCRYPT()和AES_DECRYPT()必须使用相同模式(默认ecb,但推荐显式指定cbc)、相同密钥、相同初始化向量(iv);iv长度必须为 16 字节 - 密钥不能直接传字符串:用
UNHEX('30313233343536373839616263646566')或CAST('my16byteskey...' AS BINARY)确保是二进制 - 加密结果是
VARBINARY,存入字段前务必确认列类型足够长(AES_ENCRYPT()输出长度 ≥ 原文长度 + 16) - MySQL 5.7+ 默认关闭
block_encryption_mode系统变量,需手动设为aes-128-cbc才支持iv
AES_ENCRYPT('hello', UNHEX('000102030405060708090a0b0c0d0e0f'), UNHEX('101112131415161718191a1b1c1d1e1f'))
密码存储该用什么?别自己造轮子
MySQL 本身不提供 bcrypt/scrypt/argon2 支持,所以「在数据库层做安全密码哈希」这个需求,答案很明确:不该由 MySQL 做。
- 应用层用
bcrypt.hashpw()(Python)、crypto.pbkdf2()(Node.js)或password_hash()(PHP)生成哈希,再存入 MySQL 的VARCHAR(255)字段 - 如果非要在 SQL 层处理(如 ETL 场景),至少用
SHA2('pass', 512)+ 盐值拼接,并确保盐值随机、每用户唯一、独立存储 - 绝对不要用
OLD_PASSWORD()(已弃用)、PASSWORD()(5.7+ 移除)、ENCRYPT()(仅 crypt,弱且不可移植)
敏感字段加密后查询会变慢,而且不能索引
一旦对字段用了 AES_ENCRYPT(),它就变成二进制 blob,无法走普通 B-tree 索引;想查「某个加密后的邮箱是否已存在」,只能全表扫描解密比对,性能断崖下跌。
- 若需模糊查询或范围查询,加密不是解法,应考虑字段级权限(
GRANT SELECT(col1, col2) ON db.tbl)或行级安全(MySQL 8.0+ 的CREATE POLICY) - 审计日志、备份导出等环节,加密字段仍以密文形式存在,意味着密钥管理必须覆盖整个数据生命周期——漏掉任意一环,保护就归零
- MySQL 企业版有透明数据加密(TDE),但只加密 ibd 文件,不防应用层泄露;开源版无此功能
iv 的持久化方式——它们往往硬编码在 SQL 脚本里,或者靠人工维护,一出故障就全量数据无法还原。









