PHP如何验证MySQL中存储的Dovecot生成的SSHA512格式密码
问题排查与修复方案
你现有代码的核心问题:
- PHP内置的
password_verify()仅支持PHP原生password_hash()生成的密码哈希格式(如bcrypt、Argon2、自带加盐规则的SHA系列格式),无法直接识别Dovecot使用的SSHA512自定义编码格式 - 你直接截取
{SSHA512}前缀后的内容传入password_verify()的逻辑完全不适用SSHA512的校验规则
正确的SSHA512校验逻辑说明
Dovecot存储的{SSHA512}xxx格式密码结构如下:
- 前缀
{SSHA512}为固定标识 - 后续字符串为Base64编码内容,解码后前64字节是SHA512哈希值,剩余字节就是随机盐值
修复后的代码片段
$result = mysqli_stmt_get_result($stmt); if ($row = mysqli_fetch_assoc($result)) { $stored_password = $row['password']; $pwdCheck = false; // 先校验前缀是否为SSHA512格式 if (substr($stored_password, 0, 9) === '{SSHA512}') { // 去掉前缀,取出base64编码的哈希+盐拼接串 $hash_base64 = substr($stored_password, 9); // 解码base64得到原始的哈希+盐二进制串 $hash_raw = base64_decode($hash_base64); // 前64位是SHA512哈希值,剩下的都是盐 $sha512_hash = substr($hash_raw, 0, 64); $salt = substr($hash_raw, 64); // 用用户输入的密码+提取到的盐做SHA512哈希,和存储的哈希对比 $calculated_hash = hash('sha512', $password . $salt, true); $pwdCheck = hash_equals($sha512_hash, $calculated_hash); } if ($pwdCheck == false) { $_SESSION['ERRORS']['wrongpassword'] = '密码错误'; header("Location: ../"); exit(); } else if ($pwdCheck == true) { session_start(); // 后续登录成功的逻辑
注意事项
- 哈希对比必须用
hash_equals()而不能用普通的==或===,防止时序攻击 - 如果你需要生成SSHA512格式密码存入数据库供Dovecot读取,可按规则反向实现:生成随机盐,对密码加盐做SHA512哈希,拼接哈希和盐后base64编码,加上
{SSHA512}前缀即可
内容的提问来源于stack exchange,提问作者Joshua Tyler
相关产品推荐
相关产品推荐

