PHP password_verify校验数据库存储密码哈希始终失败问题
password_verify() 数据库哈希校验失败排查方案
注册时即时校验可通过,说明password_hash()生成逻辑本身无问题,故障点必然在哈希存库、取库环节出现了字符串篡改,调整数据表排序规则对该问题无效——排序规则仅影响SQL查询时的字符串比较逻辑,不会修改字段存储、读取的原始值。按以下优先级逐一排查:
1. 最高发故障:SQL拼接导致哈希被解析篡改
你当前登录逻辑使用字符串拼接用户输入构造SQL,若注册存哈希时也使用了双引号拼接SQL的写法,哈希字符串中自带的$符号会被PHP当成变量标记解析,直接破坏哈希结构,存入数据库的内容和生成的原哈希完全不一致,这是90%同类问题的根因。
验证方法:直接打开phpMyAdmin查看user表中存储的password字段值,和注册时
password_hash()生成的原哈希逐字对比,正常bcrypt哈希固定以$2y$开头,长度为60字符,若出现字符缺失、$符号消失、内容和原哈希不符即可确认是该问题。
2. 存储环节配置错误排查
- 确认password字段类型为
varchar(255),禁止使用char类型:char类型会自动在字符串尾部补空格凑固定长度,直接破坏哈希结构 - 检查存哈希前是否对哈希值做了多余处理:包括但不限于
trim()、htmlspecialchars()、addslashes()、编码转换,任何对哈希字符串的修改都会导致校验失败 - 确认user表无未注意到的触发器,在插入、更新记录时自动修改password字段内容
3. 读取环节配置错误排查
- 数据库连接建立后,必须执行
mysqli_set_charset($conn, 'utf8mb4');设置连接字符集,若连接字符集和表字符集不匹配,读取到的哈希可能出现乱码、特殊字符被替换 - 读取到数据库中的哈希后,先打印
var_dump($row['password'])检查长度,若长度不等于60,说明读取环节存在字符转义、编码转换问题
4. 永久修复方案
所有数据库操作改用预处理语句,彻底杜绝字符串拼接带来的变量解析、转义、SQL注入问题:
注册存哈希逻辑修正
$password_hash = password_hash($_POST['password'], PASSWORD_DEFAULT); $stmt = mysqli_prepare($conn, "INSERT INTO user (username, password, active) VALUES (?, ?, 1)"); mysqli_stmt_bind_param($stmt, "ss", $_POST['username'], $password_hash); mysqli_stmt_execute($stmt);
登录查询逻辑修正
if (isset($_GET['log']) && $_GET['log'] == 1) { $username = $_POST['username']; $inputPwd = $_POST['password']; // 用预处理代替字符串拼接查询 $stmt = mysqli_prepare($conn, "select user_id, password from user where username = ? and active = 1"); mysqli_stmt_bind_param($stmt, "s", $username); mysqli_stmt_execute($stmt); $result = mysqli_stmt_get_result($stmt); $row = mysqli_fetch_assoc($result); if ($row && password_verify($inputPwd, $row['password'])) { $user_id = $row['user_id']; // 登录成功跳转逻辑 } else { echo 'failed'; } }
额外提示:你当前表单中直接输出
$_POST['username']到input的value属性,存在XSS安全风险,输出前需用htmlspecialchars()做转义处理。
内容的提问来源于stack exchange,提问作者RavenPixel
相关产品推荐
相关产品推荐

