EloquentEncryption仅实现模型层透明加解密,不支持密钥轮换、字段权限等治理功能;需通过查数据库原始值、检查trait引入、字段类型及密钥权限等验证是否生效。

直接用 RichardStyles\EloquentEncryption 是可行的,但必须清楚它只做“透明加解密”,不解决密钥轮换、字段级权限、审计日志等治理问题——它只是工具链里最靠近数据库的一环。
怎么确认 EloquentEncryption 真正在工作
别只看模型 save() 成功就以为加密生效了。常见错误是 trait 没正确引入、$encryptable 字段名拼错、或字段本身在数据库里类型不匹配(比如用了 VARCHAR 存二进制密文)。
- 先查数据库原始值:执行
SELECT password FROM users WHERE id = 1,如果看到明文(如mysecret123),说明没加密;看到乱码或 Base64 风格字符串(如U2FsdGVkX1+...),才可能已加密 - 在模型里临时加个
dd($this->attributes['password'])到setPasswordAttribute()中,确认赋值前是否已是密文 - 检查
php artisan config:clear是否执行过——配置未加载会导致Encryptabletrait 的密钥路径读取失败,静默退化为不加密
为什么 openssl_decrypt 返回 false 却没报错
这是 EloquentEncryption 底层依赖的 PHP OpenSSL 行为:失败只返回 false,不抛异常,也不写日志。你看到字段存进去了、读出来是 null 或空字符串,大概率就是这里卡住了。
- 立刻在解密逻辑前后加
error_log('OpenSSL error: ' . openssl_error_string()),不是靠猜 IV 或密钥长度 - 确认密钥文件权限:Laravel 进程用户(如
www-data)必须有读取private.key的权限,ls -l storage/keys/private.key看是否为-rw------- - 检查密钥格式:RSA 私钥必须以
-----BEGIN RSA PRIVATE KEY-----开头,不能是-----BEGIN PRIVATE KEY-----(PKCS#8 格式),后者openssl_pkey_get_private()会静默失败
加密字段能不能参与 where 查询
不能。EloquentEncryption 是模型层透明加解密,查询时 SQL 构造器拿到的是明文条件,但数据库里存的是密文,WHERE password = '123' 实际查的是密文 vs 明文,永远不匹配。
立即学习“PHP免费学习笔记(深入)”;
- 需要模糊搜索或等值匹配的字段(如身份证号),改用 AES 对称加密 + 手动管理 IV,并把加密后结果作为查询条件传入
whereRaw - 密码类字段坚决不用
where查,走password_verify()校验——这是原则,不是优化项 - 若真要支持加密字段查询,得在数据库侧建函数索引(MySQL 8.0.30+ 不推荐)或改用 searchable 加密哈希(如
hash_hmac('sha256', $idcard, $key)),但会牺牲部分安全性
真正容易被忽略的点是:加密不是一劳永逸的开关。当你要迁移密钥、升级算法、或支持多租户不同密钥时,Encryptable trait 没提供密文重加密管道。你得自己写命令批量解密再用新密钥加密——这一步没测试好,线上数据就永久锁死。



















