https仅保障传输加密,php层加密是为防护解密后到业务处理前的中间环节(如代理、日志等);应优先使用crypto_aead_xchacha20poly1305_encrypt(aead认证加密),密钥32字节、nonce必须唯一;加密数据需base64 url安全编码后存储或传输;密钥严禁硬编码,须用vault等密钥管理服务,且避免nonce重用。

HTTPS 已经加密,为什么还要在 PHP 里再加密?
因为 HTTPS 只保证「传输过程」不被窃听或篡改,不解决「端到端内容保密性」问题。比如:你用 PHP 向第三方 API 提交用户身份证号,中间经过代理、CDN、负载均衡、日志系统——这些环节可能明文记录 $_POST 或请求体。HTTPS 在到达你的服务器前就解密了,后续链路全靠你自己防护。
所以 PHP 层加密不是“重复造轮子”,而是补上 HTTPS 解密后到业务逻辑处理前这段信任空白。
PHP 中该用 openssl_encrypt 还是 crypto_aead_xchacha20poly1305_encrypt?
优先选 crypto_aead_xchacha20poly1305_encrypt(PHP 8.1+),它自带认证加密(AEAD),能同时防篡改和解密失败静默错误;而 openssl_encrypt 默认用 AES-128-CBC 时需手动加 HMAC,漏掉就可能被填充预言攻击。
-
crypto_aead_xchacha20poly1305_encrypt:密钥固定 32 字节,nonce 必须唯一且不能重用,推荐用random_bytes(24) -
openssl_encrypt若必须用:至少选AES-256-GCM模式,并严格校验$tag参数,否则等于没加密 - 别用
mcrypt_*(已废弃)、base64_encode(不是加密)、md5(不可逆但非加密)
加密后的数据怎么安全传给前端或存进数据库?
加密输出是二进制,直接塞进 JSON 或 MySQL TEXT 字段会出错。必须编码,但别用 urlencode(长度膨胀大、易被日志截断),也别用 bin2hex(翻倍体积)。
立即学习“PHP免费学习笔记(深入)”;
- 推荐
base64_encode+RFC 4648的 URL 安全变体(即替换+和/,去掉末尾=) - 存数据库时字段类型用
TEXT或MEDIUMTEXT,确保支持 UTF8MB4 编码(base64字符都在 ASCII 范围,但字段配置错了会隐式截断) - 传给前端时,放在 HTTPS 响应体里即可,不用额外套一层加密——那只是增加延迟,不提升安全性
密钥管理最容易踩的三个坑
再强的算法,密钥硬编码在代码里、写进配置文件、或者用时间戳当密钥,都等于裸奔。
- 密钥绝不能出现在 PHP 源码或
.env文件中(Git 一提交就泄露) - 生产环境用操作系统级密钥管理服务:Linux 下走
libsecret或 HashiCorp Vault;Docker 可挂载secrets,通过/run/secrets/xxx读取 - 密钥轮换要有计划:不要等泄露才换;PHP 里解密旧数据时得保留多套密钥,但新加密一律用新密钥
最常被忽略的是 nonce 重用——同一个密钥下,两次调用 crypto_aead_xchacha20poly1305_encrypt 用了相同 nonce,密文可被完全破解。务必每次生成新 random_bytes(24),并和密文一起存储或传输。











