使用PHP生成Django可接受的密码哈希不生效如何解决
错误原因
你的代码存在3个核心问题,导致生成的哈希无法被Django正常识别校验:
- 最核心的问题是
hash_pbkdf2返回值格式错误。PHP的该函数默认返回十六进制小写字符串,而Django要求哈希段是原始二进制PBKDF2计算结果的base64编码值。你直接对十六进制字符串做base64编码,得到的结果和Django计算的完全不匹配。调用函数时需要传入第6个参数true,让函数返回原始二进制结果。 - 盐值生成使用了不安全的随机源。
rand()不是密码学安全的随机数生成器,生成的盐值熵不足、可预测,既不符合密码哈希的安全要求,也和Django使用安全随机源生成盐的逻辑不符,应该替换为random_int()。 - base64编码结果保留了填充符。Django存储哈希时会去掉base64结果末尾的
=填充符,你直接使用base64_encode的带填充结果,会导致Django解析校验失败,需要手动去除末尾的填充字符。
修正后可直接使用的代码
$saltLen = 22; function generateSecureSalt($length) { $charSet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $salt = ''; $maxIdx = strlen($charSet) - 1; for ($i = 0; $i < $length; $i++) { $salt .= $charSet[random_int(0, $maxIdx)]; } return $salt; } $password = "erf1377"; $iterations = 320000; // 和Django默认PBKDF2迭代次数一致 $salt = generateSecureSalt($saltLen); // 最后一个参数传true,获取原始二进制哈希结果 $rawHash = hash_pbkdf2("sha256", $password, $salt, $iterations, 0, true); // base64编码后去除末尾的=填充符 $b64Hash = rtrim(base64_encode($rawHash), '='); $finalHash = sprintf("pbkdf2_sha256$%d$%s$%s", $iterations, $salt, $b64Hash); echo $finalHash;
效果说明
上述代码生成的哈希串完全符合Djangopbkdf2_sha256哈希器的格式要求,可直接存入用户表的password字段,Django内置的check_password方法可以正常完成密码校验。
内容的提问来源于stack exchange,提问作者leon techtippa
相关产品推荐
相关产品推荐

