openssl_encrypt/decrypt用于可逆的业务数据加密(如身份证号),而password_hash用于不可逆的密码存储;密钥须安全管理,iv每次随机生成且可与密文共存,算法、长度、选项必须严格匹配,否则静默失败。

openssl_encrypt 和 openssl_decrypt 是 PHP 加密实操的起点,但直接抄示例代码跑通 ≠ 学会加密。真正卡住人的从来不是函数怎么写,而是密钥哪来、IV 怎么存、模式选错会出什么错、以及为什么 password_hash() 不能和它们混用。
别从 md5() 或 sha1() 开始学加密
这两个函数返回的是哈希值,不是密文 —— 它们不可逆,也根本不该用于“需要解密”的场景。常见误用包括:拿 md5($password) 存用户密码后还想“找回密码”,或用它加密 API 密钥指望能还原。结果就是业务逻辑走不通,还埋下安全漏洞。
-
md5()和sha1()只适合做校验(比如文件完整性),或配合盐值做单向密码存储(但也不推荐,应改用password_hash()) - 真要加密解密,必须用对称算法(如 AES)或非对称算法(如 RSA),核心是
openssl_encrypt/openssl_decrypt或openssl_public_encrypt/openssl_private_decrypt - 硬编码密钥(比如
$key = 'mysecret123')在任何教程示例里都只是示意,上线必须剥离 —— 放环境变量、KMS 或配置中心
openssl_encrypt 的参数陷阱:模式、IV、标志位一个都不能错
调用 openssl_encrypt 失败却不报错?大概率是参数组合不合法。PHP 不会主动告诉你 IV 长度不对,而是静默返回 false,接着 openssl_decrypt 解出来空字符串或乱码。
- 先查清算法要求:
openssl_cipher_iv_length('aes-256-gcm')返回 12,openssl_cipher_iv_length('aes-256-cbc')返回 16 —— 传错长度,加密就失败 -
OPENSSL_RAW_DATA必须加:不加这个标志,函数默认返回 base64 编码结果,但openssl_decrypt期望原始二进制数据,直接喂进去会解密失败 - GCM 模式额外需要
$tag参数:它不是可选的,漏掉&$tag引用传参,openssl_encrypt就不会生成认证标签,后续无法验证完整性 - CBC 模式必须补位(padding),GCM 不需要 —— 别自己手写 PKCS#7 补位逻辑,OpenSSL 内部已处理
密钥和 IV 怎么存才不算裸奔
把密钥写死在代码里,等于把保险柜钥匙焊在锁头上。而把 IV 和密文拼一起存数据库,只要不重复用、不固定写死,就是合理做法。
- 密钥绝不能出现在代码或 Git 历史中:用
getenv('APP_ENCRYPTION_KEY')读取,密钥本身应由运维通过 secrets manager 注入容器或服务器 - IV 每次加密必须新生成(
openssl_random_pseudo_bytes()),且可以明文和密文一起存:比如 base64_encode($iv . $ciphertext),解密时先切分再用 - 别用时间戳、自增 ID、用户 ID 当 IV —— 这些可预测,会破坏 CBC/GCM 的安全性
- 密钥长度必须匹配算法:AES-256 要 32 字节,
openssl_random_pseudo_bytes(32)才对;用 16 字节去跑aes-256-cbc,函数不报错但实际降级为 AES-128
什么时候该用 password_hash(),而不是 openssl_encrypt
这个问题问错方向了 —— 它们根本不是同一类工具。混淆二者,是线上事故高发区。
-
password_hash()专用于密码存储:它自动加盐、慢哈希、抗暴力破解,且每次对同一密码输出都不同。解密?不存在。验证只用password_verify() -
openssl_encrypt用于业务数据加解密:比如数据库里的身份证号、手机号、支付令牌等,需要读取原文的字段 - 拿
password_hash()加密 API key?错。API key 需要调用时还原,必须用对称加密 - 拿
openssl_encrypt存用户密码?更错。一旦密钥泄露,所有密码瞬间可逆,远比哈希泄露危险得多
password_hash),以及密钥生命周期如何脱离代码管控。这些决策点没理清,写再多遍 openssl_encrypt 也只是在模拟正确。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











