PHP盐值和哈希SHA256用于登录密码

24

我已经在我的注册脚本中进行了密码加密并将其存储在数据库中,我必须使用它们来登录,所以我想要使用未加密的密码进行登录。我阅读了这里的一些线程,但没有任何帮助我。我该如何将其添加到我的login.php中?盐值也存储在数据库中。

这是我的register.php脚本用于加密

$hash = hash('sha256', $password1);

function createSalt()
{
    $text = md5(uniqid(rand(), TRUE));
    return substr($text, 0, 3);
}

$salt = createSalt();
$password = hash('sha256', $salt . $hash);

这是我的带有季节功能的登录页面login.php

//Create query
$qry="SELECT * FROM member WHERE username='$username' AND password='$password'";
$result=mysql_query($qry);

//Check whether the query was successful or not
if($result) {
    if(mysql_num_rows($result) > 0) {
        //Login Successful
        session_regenerate_id();
        $member = mysql_fetch_assoc($result);
        $_SESSION['SESS_MEMBER_ID'] = $member['id'];
        $_SESSION['SESS_FIRST_NAME'] = $member['username'];
        $_SESSION['SESS_LAST_NAME'] = $member['password'];
        session_write_close();
        header("location: profile.php");
        exit();
    }
    else {
        //Login failed
        //error message 
    }
else {
    die("Query failed");
}

13
你正在进行哈希运算而不是加密,两者有很大的区别。 - John Conde
3
您没有展示用户如何输入用户名/密码,以及您如何比较输入密码哈希值和存储的密码哈希值。实际上,我无法通过您当前的查询方法找出如何执行此操作,因为似乎您需要将盐值存储到数据库中,以便在比较输入与哈希密码时使用。在从数据库检索数据之前,无法知道密码哈希值是什么。此外,我不明白为什么您要两次对密码值进行哈希处理。 - Mike Brant
3
在你的代码中,你使用了一个随机盐。如果你不再知道盐的值,你如何比较密码?或者你已经存储了盐吗?-- 另外,请不要使用 mysql 函数,而是使用 mysqlipdo - andreas
5
如果您有兴趣,您应该看看全新的 PHP >= 5.5 方法,名为 password_hashpassword_verify,而不是使用自己的算法(请参见 http://www.php.net/manual/en/function.password-hash.php)。 - andreas
1
你永远不会得到未加密的密码。要检查登录,需要重新创建盐值哈希并将其与$password字段进行比较以找到匹配项。 - Digital Chris
显示剩余9条评论
6个回答

45

这些例子来自php.net。多亏了您,我也刚刚学习了新的php哈希函数。

阅读php文档以了解可能性和最佳实践: http://www.php.net/manual/zh/function.password-hash.php

保存密码哈希:

$options = [
    'cost' => 11,
];
// Get the password from post
$passwordFromPost = $_POST['password'];

$hash = password_hash($passwordFromPost, PASSWORD_BCRYPT, $options);

// Now insert it (with login or whatever) into your database, use mysqli or pdo!

获取密码哈希值:

// Get the password from the database and compare it to a variable (for example post)
$passwordFromPost = $_POST['password'];
$hashedPasswordFromDB = ...;

if (password_verify($passwordFromPost, $hashedPasswordFromDB)) {
    echo 'Password is valid!';
} else {
    echo 'Invalid password.';
}

4
这是什么巫术?在比较返回的用户密码之前,您难道不需要对其应用盐吗? - Digital Chris
9
哇,@DigitalChris,你其实不需要这样做。从php参考文档可以看到:“请注意,password_hash()返回的哈希值中包含算法、成本和盐。因此,验证哈希所需的所有信息都包含在其中。这使得验证函数能够在不需要单独存储盐或算法信息的情况下验证哈希值。”非常酷。 - Digital Chris
1
我们需要使用PASSWORD_BCRYPT常量,如答案所示,而不是PASSWORD_DEFAULT,以确保它不会在未来与现有哈希值停止工作,对吧?...此常量[PASSWORD_DEFAULT]旨在随时间变化而改变-http://php.net/manual/en/function.password-hash.php - Programster
1
不用担心,@Programster,PASSWORD_DEFAULT 将继续正常工作。停止工作的是您的数据库查询,如果您限制保存加密密码的列的长度,则无法包含它。 - George Dimitriadis

3

根据php.net的说明,自PHP 7.0.0起,Salt选项已被弃用,因此您应该使用默认生成的盐值,这样更加简单。

存储密码的示例:

$hashPassword = password_hash("password", PASSWORD_BCRYPT);

验证密码的示例:

$passwordCorrect = password_verify("password", $hashPassword);


1

0

我认为@Flo254将$salt$password1链接起来,并将它们存储到$hashed变量中。 $hashed变量进入INSERT查询,与$salt一起使用。


0

您无法登录是因为在登录时没有获得正确的盐文本。 有两个选项,第一个是定义静态盐,第二个是如果您想创建动态盐,则必须将盐存储在某个地方(即数据库中)并与用户相关联。 然后,您将连接用户盐+密码哈希字符串,现在使用此查询用户名在您的数据库表中。


-2

你不能这样做,因为你无法在精确的时间知道盐是什么。下面是一段理论上可行的代码(语法未经测试)

<?php
$password1 = $_POST['password'];
$salt      = 'hello_1m_@_SaLT';
$hashed    = hash('sha256', $password1 . $salt);
?>

当您插入:

$qry="INSERT INTO member VALUES('$username', '$hashed')";

用于检索用户:

$qry="SELECT * FROM member WHERE username='$username' AND password='$hashed'";

2
你从不存储$salt。你的理论是错误的。 - Sverri M. Olsen
3
@SverriM.Olsen 你总是存储盐 - 只是没有硬编码到代码中。重点是它是随机的,每个用户都不同。但是,它总是被存储,因为这是验证密码的唯一方法。 - Jon
2
@Jon,你误解了我的评论。这个答案中的代码从未存储$salt变量,请看INSERT查询... - Sverri M. Olsen
1
@SverriM.Olsen 我明白了。我正在澄清你的第一句话,因为如果不知道你是指用于盐的变量而不是盐本身的存储,它可能会被错误地理解,这是必需的^^ - Jon
1
@Jon,你实际上误解了Sverri的评论,否则你对他的回复就没有意义了。“你总是存储盐——只是不是硬编码到代码中”,这从一开始就不是他的观点。 - ner0
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接