2

我有一个包含以下列的 MySQL 'users' 表:uname、hash、salt 和 pwd。我正在测试一个 PHP 登录页面,该页面使用此表来获取用户访问权限。我目前还没有系统设置来注册用户,因此通过手动将数据添加到表中进行测试,如下所示.....

uname: 'testuser',
pwd: 'password'

处理检查密码的php函数如下:

function checkPwd($uname, $pwd){
    // Get the hash and salt for this user:
    $q = "SELECT hash, salt FROM users WHERE uname = '".mysql_real_escape_string($uname)."';";
    $res = mysql_query($q) or die("Could not retrieve user login data " . mysql_error());
    $tmp = mysql_fetch_assoc($res);
    $hash = $tmp['hash'];
    $salt = $tmp['salt'];
    // Hash and salt $pwd so we can make a comparison:
    $hashedInput = sha1($salt . $pwd);
    if($hash == $hashedInput) return true; // Return true if the hashed and salted $pwd matches DB entry
    return false;
}

它显然不起作用,问题是我并没有真正理解哈希和盐的做事方式。如何使用上述功能测试我的登录页面以确保安全。我必须在盐和哈希字段中输入任何内容吗?

4

4 回答 4

3

使用加密散列函数的目的是这些函数创建的值是不可逆的。因此,如果有人拥有密码的哈希值,除了暴力破解之外,没有其他可行的方法来确定密码。

但是,有一些技术可以通过使用预先计算的查找表进行时间/空间权衡来颠覆暴力破解。这些可以是已知哈希 → <em>密码对的简单查找表。或者这种查找表的扩展类型,即所谓的Rainbow 表

这就是盐的用武之地。它用于向用户密码添加额外的熵,以便散列函数的每个输入都是唯一的,从而也创建了唯一的散列:password肯定已经在查找表中,但是,xi2B9LMweH/jM8Khxedls+password当然不会。并且由于 Rainbow 表的构建方式,攻击者需要为每个唯一的盐构建一个 Rainbow 表。

请注意,盐的目的只是为了击败这种查找表攻击。如果盐是已知的,人们仍然可以进行字典攻击,或者无论如何进行蛮力攻击。如果密码错误,仍然可以猜测或暴力破解。

现在至于实现部分,最好不要重新发明轮子。因此,请查看 PHP 密码的安全哈希和盐以及如何在 PHP 中使用 bcrypt 对密码进行哈希处理?.

于 2013-06-09T21:56:54.413 回答
0

我目前还没有系统设置来注册用户,所以通过手动将数据添加到表中进行测试......它显然不起作用,

它不工作怎么办?hash为了使您的功能正常工作,您需要在与您的加盐方法(sha1行)匹配的值中插入一个值。

问题是我并没有真正理解哈希和盐的做事方式。

盐的目的是使生成的哈希值“不可预测”。哈希是一种方法,但黑客使用哈希字典暴力识别密码(彩虹表)。

盐可以与哈希一起存储在您的数据库中 - 它不需要保密。然而,对于攻击者来说,重新生成他们知道盐的字典是相当微不足道的。这就是为什么最好使用像Scrypt这样的方法。Scrypt 需要大量的 CPU 时间和内存来计算单个哈希。

Scrypt 散列可以配置为每个散列需要 100 毫秒。这意味着您每秒可以生成 10 个哈希值。常规散列方法(如 SHA1)是为提高速度而构建的。例如:通过比特币挖矿(使用散列),您可以使用硬件以低至 300 美元每秒产生 5,000 兆哈希。GPU 也擅长计算哈希。像 Scrypt 这样的方法非常适合保护密码,因为它们很难暴力破解。

如何使用上述功能测试我的登录页面以确保安全。我必须在盐和哈希字段中输入任何内容吗?

是的,您需要在哈希列中输入一个值。在测试任何登录之前,您似乎需要做更多的工作。

由于您不熟悉这些主题,我强烈建议您使用一个通用的 PHP 框架来为您处理这些事情。至少检查一下这些框架如何实现身份验证。安全堆栈交换也是一个很好的资源。

于 2013-06-09T22:14:39.870 回答
-1

你只需要“salt”和“password”,Salt 的作用是创建一个随机字符串值,像公钥一样使用它来加密密码。

例如: $salt = base_convert(sha1(uniqid(mt_rand(), true)), 16, 36);

现在你可以用这个 Salt 来加密你的密码: $pwd = sha1($salt . $POST['pwd']); 然后将 $pwd 和 $salt 保存在数据库中。

现在,如果您想检查登录:您对数据库中的唯一值(电子邮件、用户名)进行 SELECT 查询,然后通过 solt 加密输入的密码并进行测试。

编辑:

对于 Salt 行:我们在您喜欢的任意一对数字之间为 uniqid (php.net/manual/fr/function.uniqid.php) 创建一个随机值,我选择 16 和 36,然后使用 sha1 使其更强大,最后我们用 php.net/manual/fr/function.base-convert.php 清理我们的 Salt

希望它有所帮助。

于 2013-06-09T20:52:24.167 回答
-1

标准密码安全方法是这样的:

您的服务器端数据库应为每个用户存储两列:用户名和哈希。如果您想为每个用户使用单独的盐,那么也可以存储它。为站点设置一个盐并在哈希中包含用户名会更简单。如果您不想在哈希中包含用户名,则建议为每个用户使用单独的盐(如果需要,它可以从用户名和特定于站点的东西中计算出来,或者 cah 只是随机的)。

最重要的一点:永远不要将密码存储在数据库中。

当用户注册并选择密码时,从密码+盐+用户名(或密码+唯一盐,如果你要走那条路)构建一个字符串,然后通过加密安全的哈希函数运行它。MD5 已经过时并且不是很安全。SHA1 可能没问题。SHA256 会更好。不要使用分组密码 AES——它们的设计目的不是防碰撞。将此哈希的结果存储在表中。

当用户下次登录时,获取他的用户名和密码,添加你的盐,并计算相同的哈希函数。将其与存储在数据库中的进行比较。如果他们匹配,让她进来。如果你做对了,即使你的数据库被发布了,没有人可以使用它找到任何人的密码。

为了获得额外的安全性(如果你做对了其余的事情,现在可能有点过分了,但有利于未来的验证),请使用故意计算缓慢且复杂的哈希函数。一种方法是简单地迭代你的散列函数几百次。另一个是使用像 scrypt 这样的内存难题。

加盐的目的是防止“彩虹表”攻击,在这种攻击中,潜在的攻击者预先计算了数十亿个潜在密码的哈希值,而不必通过蛮力单独破解它们。

于 2013-06-09T22:05:48.883 回答