tp6密码安全核心是前端rsa加密防传输明文、后端bcrypt哈希防存储泄露。前端用jsencrypt+2048位公钥加密password字段,后端用openssl_pkcs1_oaep_padding私钥解密并注入明文;解密后必须调用hash::make()生成带盐bcrypt哈希($2y$开头,存入varchar(60)字段),禁用md5、aes加密存库等错误做法。

TP6 接口密码加密存储的核心是:前端传输阶段防明文、后端存储阶段防泄露,两者缺一不可。不能只做前端 RSA 加密而忽略后端 bcrypt 哈希,也不能只存哈希却让密码在 HTTP 请求中裸奔。
前端传输必须用 RSA 加密
用户在登录表单输入的密码,绝不能以明文形式通过网络发送。需在提交前用公钥加密:
- 使用 JSEncrypt 库,在 login 页面初始化时加载公钥(2048 位,含完整 BEGIN/END 标记)
- 点击登录时,对 password 字段单独加密:
encrypt.encrypt($('#password').val()) - 后端收到的是密文字符串,需用私钥解密还原明文,再交由认证逻辑处理
- 解密必须使用
OPENSSL_PKCS1_OAEP_PADDING填充方式,避免填充攻击 - 解密后建议用
$request->merge(['password' => $plainPassword])注入明文,保持后续逻辑不变
后端存储必须用 bcrypt 哈希
解密得到的明文密码,绝不能直接存库或二次 AES 加密。必须用不可逆、带盐的哈希算法固化:
- TP6 默认采用
bcrypt,密码字段值以$2y$、$2a$或$2b$开头 - 生成哈希应统一调用
think\facade\Hash::make($password),它自动处理盐值和轮数 - 不要手写
password_hash($password, PASSWORD_BCRYPT),除非你明确控制cost参数 - 数据库 password 字段类型设为
VARCHAR(60)或更长,确保容纳完整哈希串 - 验证时用
Hash::check($input, $hashed),而非 strcmp 或自定义比对
禁止踩的典型坑
这些做法看似“加了密”,实则破坏安全链条或引入新风险:
- 把 RSA 密文直接存进 password 字段——导致无法用框架认证机制,且密文可被重放
- 用
md5()、sha1()或password_hash()的非 bcrypt 模式——抗碰撞能力弱,易被彩虹表破解 - 在模型里写
setPasswordAttr对密码做 AES 加密——混淆了“传输保护”和“存储保护”的边界 - 前端加密 + 后端再
md5(md5($pwd))——属于无效叠加,还可能因重复哈希导致验证失败 - 把私钥硬编码在 PHP 文件里或暴露在 JS 中——私钥必须严格保密,仅后端可信环境可读
验证与调试要点
上线前务必确认三件事是否闭环:
- 抓包检查请求体中的 password 字段是否为 Base64 格式密文(长度约 256 字符),不是明文也不是 MD5
- 查数据库 password 字段是否为 60 字符左右、以
$2y$开头的字符串 - 用已知账号重试登录,观察日志中是否依次出现「RSA 解密成功」「Hash::check 返回 true」
- 故意输错密码,确认返回的是“用户名或密码错误”,而非“解密失败”或“哈希格式异常”等泄露信息











