使用password_verify验证数据库哈希密码失败的求助
问题诊断与修复方案
我一眼就揪出了几个关键问题,咱们一步步来解决:
1. 登录逻辑完全错误(最核心的问题)
你的登录代码犯了一个根本性的逻辑错误:你试图用用户输入的明文密码去匹配数据库里的哈希密码字段,这显然不可能查到结果——数据库里存的是经过password_hash处理后的哈希值,不是明文啊!
看你这段错得离谱的代码:
$stmt = $db->prepare('SELECT password FROM users WHERE password = :password'); $stmt->execute(array(':password' => $password)); $row = $stmt->fetch(PDO::FETCH_ASSOC);
这里的$password是用户输入的明文,而数据库里的password字段是60位的哈希串,所以$row肯定是空的,后续的password_verify自然会直接失败。
正确的登录逻辑应该是这样:
- 根据用户输入的邮箱,从数据库取出对应的哈希密码
- 用
password_verify把用户输入的明文密码和取出的哈希做比对
修正后的登录代码:
$mail = htmlspecialchars_decode($_POST['mail'], ENT_QUOTES); if(!filter_var($mail, FILTER_VALIDATE_EMAIL) and !empty($_POST['mail'])) { $error[] = 'Please enter a valid email address'; } // 第一步:通过邮箱找到对应的用户哈希密码 $stmt = $db->prepare('SELECT mail, password FROM users WHERE mail = :mail'); $stmt->execute(array(':mail' => $mail)); $row = $stmt->fetch(PDO::FETCH_ASSOC); // 先检查邮箱是否存在 if(empty($row)){ $error[] = 'Email does not exist in our system.'; } else { // 邮箱存在,验证密码 $password = $_POST['password']; if(password_verify($password, $row['password'])) { $error[] = 'Password provided is good.'; // 这里可以继续写登录成功后的逻辑,比如设置session、跳转页面等 } else { $error[] = 'Incorrect password.'; } }
2. 数据库中哈希密码重复的问题
你提供的数据库示例里,每个哈希密码都是重复拼接的(比如football对应的是两个完全一样的60位哈希串连在一起),这会直接导致password_verify验证失败——因为哈希值被篡改了,不再是password_hash生成的原始串。
可能的原因:
- 注册代码里有没有重复插入哈希值的逻辑?虽然你的注册代码看起来
bindValue(':password', $hashedpassword)是对的,但要排查是否有其他代码重复写入这个字段。 - 是不是测试时手动修改过数据库的值?或者代码存在重复执行插入的情况?
- 虽然你设置的
varchar(255)足够存储60位哈希,但如果存储时出现重复,大概率是代码逻辑问题。
修复建议:
- 重新测试注册流程,确保数据库里只存储单个60位的哈希串(比如
$2y$10$q0Y8Mfdl75Dt8op7WaqQM.t5y4LMO6gfYwmbycL1xRMiUUQu8dtWm),而不是重复拼接的字符串。 - 注册时可以去掉多余的
echo $hashedpassword,避免干扰,确保插入的是正确的哈希值。
3. 其他细节提醒
- 注册和登录时,不要对用户输入的密码做额外的转义或编码处理(比如
htmlspecialchars),直接传给password_hash或password_verify即可。 - 建议开启PDO的错误模式,方便调试:
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);,这样能及时发现数据库操作中的隐藏错误。
按上面的步骤修改后,密码验证应该就能正常工作了。
内容的提问来源于stack exchange,提问作者Motambe Markumbo
相关产品推荐
相关产品推荐

