最近我一直在对密码学进行大量研究。这让我发现,我们不仅salt,还有pepper(是的,我真的只是发现了胡椒)。
这一切都是在我继承了一个密码未经过哈希处理的项目时开始的。即使作为一个n00b,我知道这只是愚蠢的 我对哈希有基本的了解,但我所知道的是apparently outdated。
我的原始哈希和盐是通过以下方式实现的:
MD5
这很好用,但我倾向于使用更好的技术
我希望尝试的新方法是使用PHP的password_hash和password_verify。
创建快速测试后,我可以看到我可以在给定哈希上使用password_verify
返回一个真值。令我困惑的一件事是盐进来的地方?
在文档中我可以看到有一个选项可以在options数组中指定salt,但从PHP 7.0开始不推荐使用。
我创建了一些代码(未经测试)只是为了演示。见下面的代码。
<?php
$pepper = "myPepper";
function register($username, $password)
{
// add the pepper
$password .= $pepper;
// hash the password
$hash = password_hash($password, PASSWORD_BCRYPT, ["cost" => 10]);
// insert into table
$query = $mysqli->prepare("INSERT INTO users(username, password) VALUES(?, ?)");
$query->bind_param("ss", $username, $hash);
// check the success
if ($query->execute())
return true;
else
return false;
}
function login($username, $password)
{
// create the query
$query = $mysqli->prepare("SELECT password FROM users WHERE username = ?");
$query->bind_param("s", $username);
// check if successful
if ($query->execute())
{
// get password from the database
$query->store_result();
$query->bind_result($hash);
$query->fetch();
// verify the passwords are the same
if (password_verify($password . $pepper, $hash))
return true;
else
return false;
}
}
?>
register
功能这些功能都非常基础,因为我只想说明一点。
此函数采用一些参数(在本例中为username
和password
并将它们添加到数据库中。
现在,我知道如何将我的胡椒添加到密码中,因为这是一个简单的连接,但盐是随机生成但从未返回意味着我不知道它是什么。
login
功能同样,它的作用非常基础。
由于我之前没有使用password_verify
,因此我不完全确定使用最佳方法来获取用户密码。
使用我的旧登录脚本,它们看起来像这样:
function login($username, $password)
{
// create the query
$query = $mysqli->prepare("SELECT salt FROM users WHERE username = ? AND password = ?");
$pass = md5($password);
$query->bind_param("ss", $username, $password);
// check if successful
if ($query->execute())
{
$query->store_result(); // store result to gain access to num_rows
// verify if password and usernames match
if ($query->num_rows == 1)
return true;
else
return false;
}
}
我只是将密码哈希并将其作为参数传递给SQL查询 使用bcrypt,我必须从表中提取密码,然后在另一个查询中使用它。 (至少这是我认为我目前必须做的事情。)
如果我因缺乏知识和/或对我的知识缺乏解释而冒犯任何人,我道歉。
我渴望知识。所以我不知道,我想知道。 (显然在某种程度上,我喜欢学习计算机,系统和编程等)。
密码哈希这些天是必不可少的,正确的是非常重要的,这就是我写这篇论文问题的原因。
login
和register
的基本示例中,我实施了password_hash
和password_verify
吗?根据所有评论,我只想发布此更新。
如上所述我喜欢学习,所以当我遇到这个功能时,它开始让我困惑,因为我不知道发生了什么。
我将发布一些示例,尝试有效地让每个人都感到困惑。
让我们以此脚本为例:
<?php
// everything below is hard coded for simplicity (would actually be extracted from a database)
$password = "myPassword"; // the password from the database
$salt = "mySalt"; // I have hard coded this for simplicity
$hash = md5($salt . $password);
// check login status
if (md5($salt . $_POST["password"]) == $hash)
return true;
else
return false;
?>
在这个例子中,我理解哈希是如何工作的。
我正在使用salt存储密码并对其进行哈希处理。然后我用盐和散列检查发布的密码。如果两者匹配,那么我成功登录,否则登录失败。
现在,让我们来看下面的例子。
<?php
// everything below is hard coded for simplicity (would actually be extracted from a database)
$password = "myPassword"; // the password from the database
$hash = password_hash($password, PASSWORD_BCRYPT, ["cost" => 10]); // salt is taken care of
// check login status
// again I am keeping this so simple (it might not work per se but I just want to learn about the functions)
if (password_verify($_POST["password"], $hash))
return true;
else
return false;
?>
当我跑password_verify
时,我开始感到困惑。
我理解默认情况下在password_hash
中处理了salt,但在第一个示例中我知道salt,因此我可以使用发布的密码执行哈希以检查它们是否匹配。
为什么password_verify
成功验证发布的密码而没有给我盐?
当然,盐被设计为使每个密码都是唯一的,但不知何故password_verify
将成功。我使用var_dump
转储从password_hash
生成的哈希值,并在刷新时更改。这真的是混乱的来源。如果"test"
的哈希值在每次刷新时都可以更改为不同的哈希值,那么password_verify
知道所发布的密码是否正确?
我知道我可以编写一个函数来验证用户的密码。我真正想知道的是PHP的password_verify
每次如何设法验证true
,尽管我的哈希值会随着每次刷新而改变。
注意:我知道我会将密码存储在数据库中,因此刷新不会成为问题,但我这样做是为了尝试理解该功能。
@RiggsFolly我知道盐是为我做的。问题是&#34;验证函数如何知道哈希函数中创建的随机盐以验证为真?&#34;
@RiggsFolly我知道salt选项已被弃用。如果没有(我能够通过盐),我想我会更多地了解这个功能。验证函数的整个想法成功地验证了密码没有知道盐的哈希实际上是我的想法。
也许我只是愚蠢。
@Alex Howansky盐是如何回归的? $hash = $2y$10$Vaj4ZonpRJjE6kmfQffvOOeIVW3ZV31JJYVY79GtZ3GtioZKtDwku
之类的字符串表示什么都没有,但某种程度上password_verify("test", $hash")
会返回true
。
@Machavity读完链接之后,我可以看到salt在哈希的开头,但是盐怎么能在最后的哈希中呢?我为我的困惑和明显的愚蠢而道歉,但我只是希望理解密码哈希,以便我为将来的使用做好更充分的准备。
@Fred -ii-这些自定义函数对于示例来说很简单(我没有想要链接整个代码页)。话虽如此,我目前的用法是在一个名为User
的自定义类中,我有一个名为private
的{{1}}变量存储$conn
连接。然后,我使用mysqli
来访问数据库
范围界面不好吗?在自定义类中存储连接的首选方法是什么?