我什么时候需要使用 password_needs_rehash()?
When do I need to use password_needs_rehash()?
我有一个用于登录应用程序的处理文件。我要么不明白 password_needs_rehash()
的目的,要么它不起作用。登录正在验证并将我传递到正确的页面。但是我什至无法得到代码来回显新的哈希值。
我这样做正确吗?
if
不会抛出一个新的散列,因为它不需要重新散列吗?如果是这样,如果密码已正确散列并存储在数据库中,何时需要重新散列密码?
我的加工文件如下:
$email = $_POST["li_email"];
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
// set the PDO error mode to exception
$stmt = $conn->query("SELECT * FROM users WHERE email='$email'");
$stmt->execute();
while($row=$stmt->fetch()){ //for each result, do the following
$hash = $row['hash'];
$userPassword = $_POST["li_password"];
if (password_verify($userPassword, $hash)) {
if ( password_needs_rehash($hash, PASSWORD_DEFAULT, ['cost' => 12]) ) {
$newhash = password_hash($userPassword, PASSWORD_DEFAULT, ['cost' => 12]);
echo $newhash;
}
} else {
header('Location: http://' . $_SERVER['HTTP_HOST'] . '?error=loginfailed');
exit();
}
}
} catch(PDOException $e) {
echo $sql . "<br>" . $e->getMessage();
}
$conn = null;
感谢您的帮助!
函数password_needs_rehash()
只需要改变$options
,通常指的是cost
。
成本越高,散列密码所需的 CPU 时间就越多,但破解密码就越困难。如果您更改托管或转移到基于云的系统,其中多台计算机可以为您计算哈希值,您可以自行决定增加它。
您只需要在用户登录时检查密码是否需要重新哈希,因为如果您更改了 $options
,password_verify()
仍然可以验证密码.如果此时 password_needs_rehash()
returns 为真,请将 password_hash()
与新选项一起使用并替换旧哈希。
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
$stmt = $conn->prepare($sql = "SELECT * FROM users WHERE email=?"); // otherwise $sql is not defined in catch()
if($stmt->execute([$_POST["li_email"]])){
// preventing sql injection
if(($data = $stmt->fetch()) != false){
// only expecting 1 row from db since an email should be unique.
if(password_verify($_POST["li_email"], $data['hash'])){
// valid login
if(password_needs_rehash($data['hash'], PASSWORD_DEFAULT, $options = ['cost' => 12])){
$newhash = password_hash($_POST["li_email"], PASSWORD_DEFAULT, options);
// store new hash in db.
}
} else {
header('Location: http://' . $_SERVER['HTTP_HOST'] . '?error=loginfailed');
exit();
}
} else {
// no results
}
} else {
// query failed
}
} catch(PDOException $e) {
echo $sql . "<br>" . $e->getMessage();
}
仅作记录,是上述代码的合理重构版本,删除了一些漏洞和不一致之处。
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
$conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$stmt = $conn->prepare("SELECT * FROM users WHERE email=?");
$stmt->execute([$_POST["li_email"]]);
$data = $stmt->fetch();
if($data && password_verify($_POST["li_password"], $data['hash'])) {
if(password_needs_rehash($data['hash'], PASSWORD_DEFAULT, $options = ['cost' => 12])){
$newhash = password_hash($_POST["li_password"], PASSWORD_DEFAULT, options);
// store new hash in db.
}
} else {
header('Location: http://' . $_SERVER['HTTP_HOST'] . '?error=loginfailed');
exit();
}
一些要点:
- 无需向黑客提示用户名和密码的不同错误消息。
- 应严格避免数据库结构泄漏
- 没有必要查看 SQL 错误消息,因为它已经在代码中
- 如果执行失败,则为系统错误,应相应处理
我有一个用于登录应用程序的处理文件。我要么不明白 password_needs_rehash()
的目的,要么它不起作用。登录正在验证并将我传递到正确的页面。但是我什至无法得到代码来回显新的哈希值。
我这样做正确吗?
if
不会抛出一个新的散列,因为它不需要重新散列吗?如果是这样,如果密码已正确散列并存储在数据库中,何时需要重新散列密码?
我的加工文件如下:
$email = $_POST["li_email"];
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
// set the PDO error mode to exception
$stmt = $conn->query("SELECT * FROM users WHERE email='$email'");
$stmt->execute();
while($row=$stmt->fetch()){ //for each result, do the following
$hash = $row['hash'];
$userPassword = $_POST["li_password"];
if (password_verify($userPassword, $hash)) {
if ( password_needs_rehash($hash, PASSWORD_DEFAULT, ['cost' => 12]) ) {
$newhash = password_hash($userPassword, PASSWORD_DEFAULT, ['cost' => 12]);
echo $newhash;
}
} else {
header('Location: http://' . $_SERVER['HTTP_HOST'] . '?error=loginfailed');
exit();
}
}
} catch(PDOException $e) {
echo $sql . "<br>" . $e->getMessage();
}
$conn = null;
感谢您的帮助!
函数password_needs_rehash()
只需要改变$options
,通常指的是cost
。
成本越高,散列密码所需的 CPU 时间就越多,但破解密码就越困难。如果您更改托管或转移到基于云的系统,其中多台计算机可以为您计算哈希值,您可以自行决定增加它。
您只需要在用户登录时检查密码是否需要重新哈希,因为如果您更改了 $options
,password_verify()
仍然可以验证密码.如果此时 password_needs_rehash()
returns 为真,请将 password_hash()
与新选项一起使用并替换旧哈希。
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
$stmt = $conn->prepare($sql = "SELECT * FROM users WHERE email=?"); // otherwise $sql is not defined in catch()
if($stmt->execute([$_POST["li_email"]])){
// preventing sql injection
if(($data = $stmt->fetch()) != false){
// only expecting 1 row from db since an email should be unique.
if(password_verify($_POST["li_email"], $data['hash'])){
// valid login
if(password_needs_rehash($data['hash'], PASSWORD_DEFAULT, $options = ['cost' => 12])){
$newhash = password_hash($_POST["li_email"], PASSWORD_DEFAULT, options);
// store new hash in db.
}
} else {
header('Location: http://' . $_SERVER['HTTP_HOST'] . '?error=loginfailed');
exit();
}
} else {
// no results
}
} else {
// query failed
}
} catch(PDOException $e) {
echo $sql . "<br>" . $e->getMessage();
}
仅作记录,是上述代码的合理重构版本,删除了一些漏洞和不一致之处。
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
$conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$stmt = $conn->prepare("SELECT * FROM users WHERE email=?");
$stmt->execute([$_POST["li_email"]]);
$data = $stmt->fetch();
if($data && password_verify($_POST["li_password"], $data['hash'])) {
if(password_needs_rehash($data['hash'], PASSWORD_DEFAULT, $options = ['cost' => 12])){
$newhash = password_hash($_POST["li_password"], PASSWORD_DEFAULT, options);
// store new hash in db.
}
} else {
header('Location: http://' . $_SERVER['HTTP_HOST'] . '?error=loginfailed');
exit();
}
一些要点:
- 无需向黑客提示用户名和密码的不同错误消息。
- 应严格避免数据库结构泄漏
- 没有必要查看 SQL 错误消息,因为它已经在代码中
- 如果执行失败,则为系统错误,应相应处理