如何避免将空字节传入Bcrypt(password_hash)函数?
问题:生成“记住我”安全令牌时,空字符导致password_hash抛出ValueError
我有一个用于生成浏览器登录“记住我”安全令牌的脚本,代码如下:
$token = random_bytes(32);
随后将该令牌存入数据库,用于后续比对,相关代码如下:
$sql = " INSERT INTO auth_tokens (user, user_email, auth_type, selector, token, expires_at) VALUES (?, ?, 'remember_me', ?, ?, ?) "; $stmt = mysqli_stmt_init($conn); $hashedToken = password_hash($token, PASSWORD_DEFAULT); // ... more param definitions mysqli_stmt_bind_param($stmt, $s, $username, $email, $selector, $hashedToken, $date); mysqli_stmt_execute($stmt);
问题在于,random_bytes()有时会生成空字符,进而导致password_hash()抛出错误。该致命ValueError是近期添加到Bcrypt中的:
PHP Fatal error: Uncaught ValueError: Bcrypt password must not contain null character in *** Stack trace:***: password_hash() {main} thrown in ***
请问预防random_bytes()生成的空字符传入的正确方法是什么?直接使用str_replace('\0', '', $token)是否合理?
解决方案
为什么直接用str_replace('\0', '', $token)不合理
直接替换空字符会破坏令牌的安全性:
random_bytes(32)生成的是固定32字节的二进制数据,替换空字符后长度会缩短,导致令牌的随机性(熵)下降,降低抗破解能力。- 空字节的数量和位置不可控,可能导致不同的原始令牌被处理成相同的字符串,增加碰撞风险。
正确的处理方式:二进制转文本编码
random_bytes()生成的是二进制字符串,要彻底避免空字节问题,最安全的做法是将其转换为Base64或Hex编码的纯文本字符串——这种转换是无损的,既保留了原始数据的全部熵,又不会产生空字节。
示例1:使用Base64编码
$token = random_bytes(32); // 将二进制令牌转换为Base64编码的文本字符串 $tokenText = base64_encode($token); // 安全传入password_hash $hashedToken = password_hash($tokenText, PASSWORD_DEFAULT); // 存入数据库的逻辑保持不变 $sql = " INSERT INTO auth_tokens (user, user_email, auth_type, selector, token, expires_at) VALUES (?, ?, 'remember_me', ?, ?, ?) "; $stmt = mysqli_stmt_init($conn); mysqli_stmt_bind_param($stmt, 'ssssss', $username, $email, $selector, $hashedToken, $date); mysqli_stmt_execute($stmt);
示例2:使用Hex编码
$token = random_bytes(32); // 将二进制令牌转换为十六进制文本字符串 $tokenText = bin2hex($token); $hashedToken = password_hash($tokenText, PASSWORD_DEFAULT); // 后续存储逻辑同上
后续比对注意事项
当浏览器返回“记住我”令牌时,需要确保传入password_verify的是相同编码格式的文本字符串,比如:
// 假设从Cookie中获取的是Base64编码的令牌 $receivedToken = $_COOKIE['remember_token']; // 从数据库取出对应的哈希值 $storedHashedToken = /* 查询数据库的结果 */; if (password_verify($receivedToken, $storedHashedToken)) { // 令牌验证通过 }
内容的提问来源于stack exchange,提问作者Fid
相关产品推荐
相关产品推荐

