我应该存储密码的哈希值吗?

时间:2010-06-14 14:39:41

标签: php encryption passwords

用户系统和密码:我正在查看MD5的内容,我想知道密码的正常/良好做法是什么。现在,我认为人们会对密码进行超级加密并存储哈希值。如果是这样,密码检查如何工作?我只是让输入密码再次通过加密过程,然后用存储的密码检查哈希,对吗?

这个问题可能与上述内容相矛盾,但我的盐是否应该是随机生成的值?如果是的话,什么时候有用?

编辑除了密码之外,在用户系统中,还应该将其他哪些内容加密为良好做法?他们是否加密用户名或其他任何内容?

第二次编辑:什么是单向哈希?我的意思是,从技术上讲,我可以不对我的源代码进行反向工程吗?也许这是一个糟糕的问题,因为我对单向哈希知之甚少。

11 个答案:

答案 0 :(得分:10)

首先你创造一个盐。

注意示例用PHP编写

// Setup a salt, this isn't "random" but it doesn't really have to be
$salt = sha1(microtime());

然后加密密码

// First we hash the password, then XOR it with the salt hashing the result
$hash = sha1(sha1($password) ^ $salt);

$hash$salt存储在数据库中。

当用户输入密码时,将其与散列

进行比较
if(sha1(sha1($entered_password) ^ $salt) == $hash)
    // Correct password

从不以可逆格式存储密码。另外,我建议不要使用MD5作为哈希。

  

编辑:除了密码之外,在用户中   系统,还应该加密什么   作为一个好习惯?他们加密吗?   用户名还是其他什么?

密码未加密,会进行哈希处理。将哈希(非常简单化)描绘成需要数字并将其乘以10的东西。假设我想哈希数字30。我会说30*10并将300作为30的“哈希”。请注意,如果不知道哈希函数的工作原理,则无法从30派生300

这是一个非常简单的“哈希”,如果你知道它总是乘以十,那么你可以很容易地逆转它。 Now take a look at the SHA1 hash function。它的很多更复杂。它不能简单地逆转。

你会发现除密码哈希之外很少有任何东西,没有任何东西是加密的。加密数据库所需的开销将是巨大的。

假设你可以对用户名应用类似的salt / hash模式,但是你有陷阱。如果您想在代码中的某个位置使用该用户名,该怎么办?如果您想检查以确保它是独特的桌子怎么办?

  

第二编辑:什么是单向哈希?一世   从技术上讲,我不能逆转   设计我的源代码?也许这是   一个糟糕的问题,因为我不知道   很多关于单向散列的事情。

见上文(or click here)。单向哈希就是这样。单向映射。 A => B而没有别的。除了B !=> A之外,AB不能是任何内容。

有人提到了XOR操作的性能。虽然我觉得性能在很大程度上可以忽略不计,但我还是进行了快速测试。

function microtime_float()
{
    list($usec, $sec) = explode(" ", microtime());
    return ((float)$usec + (float)$sec);
}

现在运行

$start_time = $this->microtime_float();

for($i = 0; $i < 100000; $i++)
{
 $sha = sha1(sha1(microtime()) . sha1(microtime()));
}

$end_time = $this->microtime_float();

echo "1000 in " . ($end_time-$start_time) . " for CAT\n";


$start_time = $this->microtime_float();

for($i = 0; $i < 100000; $i++)
{
 $sha = sha1(sha1(microtime()) ^ sha1(microtime()));
}

$end_time = $this->microtime_float();

echo "1000 in " . ($end_time-$start_time) . " for XOR\n";

根据需要重复。 initial writeup使用错误日志,我得到以下结果:

1000 in 0.468002796173 XOR
1000 in 0.465842008591 XOR
1000 in 0.466115951538 XOR
1000 in 0.498080968857 CAT
1000 in 0.506876945496 CAT
1000 in 0.500174045563 CAT

答案 1 :(得分:1)

从不以可逆方式存储密码,请始终使用One-Way-Hashes。通过散列输入的密码并检查彼此的两个哈希来检查是否正常工作。

答案 2 :(得分:1)

使用密码的标准做法是不在任何地方存储原始密码。 Unix密码曾经使用随机盐加密“crypt”。 salt本身存储在加密密码的前两个字符中。当用户输入密码时,系统会使用加密密码的两个字符作为盐来加密输入的密码,如果加密结果与存储的加密密码相同,则匹配。使用MD5密码可以完成类似的操作。

这就是好网站永远不会通过电子邮件向您发送密码的原因,而是将您的密码重置为一次性密码 - 因为他们不知道您的密码。

要稍微扩展一下:MD5哈希是一个单向函数 - 如果你使用相同的哈希值散列相同的值,但你不能将哈希值以某种方式转换为值。两个值产生相同散列的机会很小但很有限(初始字符串越大或散列越小,机会越高),但是他们选择散列算法以使两个字符串的人有机会选择因为密码会散列到几乎无穷小的相同值。你可以把单向哈希想象成一个绞肉机 - 你可以看看你的绞肉机出来的肉,看看它是牛,羊或猪,但你不能通过其他方式传递它找回一头牛。

因此,没有人可以恢复你的密码,因为它从不存储在他们系统的任何地方,只是它的散列。

答案 3 :(得分:1)

  

这个问题可能与此相矛盾   以上,但我的盐应该是一个   随机生成的值?如果是的话,何时   它可能有用吗?

盐应该是随机的。它们唯一的用途是对哈希进行暴力攻击要贵得多。一个叫做“彩虹表”的东西(这是一个数据库的奇特名称,其中有人预先将一大堆可能的密码打包,如果你知道哈希就让你查找密码)可以获取无密码的密码哈希并转向在许多情况下,它们会在几分之一秒内变成密码。

中等大小的盐会以指数方式增加预先计算的暴力攻击的复杂性。对于盐中的每一位随机数据​​,您将预先计算的暴力攻击所需的时间加倍。对于数据库中的每个唯一salt值,攻击者必须在攻击受该盐保护的密码时重新开始。

如果每个用户的密码都有1kB的随机盐,那么预计算的哈希值就会超出窗口。但是,您不会影响强制使用单个用户密码所需的时间。

你可以使蛮力攻击者的生活更艰难的一种方法是使哈希过程计算密集(例如5000轮sha1(盐+ sha1(盐+ sha1(盐+密码))))。您只需为每次登录尝试执行此操作。攻击者必须为他们想要猜测的每个salt +密码组合执行此操作。你必须决定这是否值得满足你的需求。答案可能是否定的。

  

编辑:除了密码之外,在用户中   系统,还应该加密什么   作为一个好习惯?他们加密吗?   用户名还是其他什么?

我是偏执狂,但我会说,当用户未登录时,网站所有者不需要的任何信息都应该使用用户密码的衍生物进行加密。这样攻击者就无法访问,因为你没有访问权限。

例如,对于在线订单处理系统,您可能需要他们的邮寄地址,他们的姓名和最近未加密的订单,但他们的订单历史记录和喜欢的颜色可能会使用他们的帐户密码加密。

请注意,如果您这样做,并且他们丢失了密码,受保护的信息也会丢失。

  

第二编辑:什么是单向哈希?一世   从技术上讲,我不能逆转   设计我的源代码?也许这是   一个糟糕的问题,因为我不知道   很多关于单向散列的事情。

哈希是一种系统地丢弃信息的方法。假设你从一个字符串开始,并通过扔掉除了大约每四个字符之外的所有字符来产生“srflcdos”。我“散布”的文字可能是:“如果鱼平静地躺着,那就是长矛。不要坐!”,或者可能是:“supercalifragilisticexpialidotious”。无论如何都无法证明这一点。

加密哈希进行更多混合和其他转换以及丢弃,以使它们对于少量输入数据更安全,并避免泄漏任何有关输入数据的事实。作为不安全散列的示例,如果您知道每当输入包含字母A时,散列的12位为1,那么您将公开有关原始文本的信息,并且结果不是加密安全散列。 / p>

原则是,如果在每次转换之间丢弃对逆转先前转换至关重要的信息,则无法对流程进行逆向工程。无论您输入1位还是12 PB的信息,MD5sum都会产生128位输出。你显然无法将12 PB压缩成128位,因此在计算哈希的过程中信息显然会被丢弃。

答案 4 :(得分:0)

您应该存储密码的哈希值而不是实际的可读字符串,还应考虑使用“Salting”以获得额外的安全性

答案 5 :(得分:0)

这个主题有很多变化。

如需了解更多信息,请阅读:http://en.wikipedia.org/wiki/Digest_access_authentication

然后阅读:http://tools.ietf.org/html/rfc2617

通常:您只存储摘要。从来没有密码。

遵循RFC2617,您应该存储用户名,域和密码的摘要。

客户端(“代理人”)获取用户名,密码,领域等,并创建一个摘要,并将其发送到您的服务器。

您的服务器根据用户名查找摘要版本。

如果他们的摘要==保存在服务器中的摘要,则表示您同意密码(以及其他所有内容)。

如果他们的摘要!=保存在服务器中的摘要,则您不同意密码(或其他内容)。这意味着他们没有正确的域名或用户名,或他们没有得到正确的nonce,或其他出错的地方。他们不可信任。

完整的RFC2617包含其他数据来计算其他内容的摘要和密码摘要,以确保客户端正在做出响应。

答案 6 :(得分:0)

  

第二编辑:什么是单向哈希?我的意思是,从技术上讲,我可以不对我的源代码进行反向工程吗?也许这是一个糟糕的问题,因为我对单向哈希知之甚少。

密码学中的“单向”意味着“难以反转”。简单地说,这意味着如果我给你sha1(password),你就无法在任何合理的时间内找到password

这称为computationally one-way。许多人将此与另一种单向(来自数学)意义"not one-to-one"的定义相混淆,这在此不适用。

答案 7 :(得分:0)

我强烈建议不要使用MD5。有关详细信息,请阅读Wikipedia section [MD5] Security。我建议改用SHA-1哈希算法。

答案 8 :(得分:0)

如果可以,请避免使用MD5哈希值,因为它有很大的缺陷。

替代方案是SHA1,甚至更好的SHA256或SHA512。

答案 9 :(得分:-1)

存储散列密码的原因是,如果有人设法获取用户表中的数据,他们仍然无法登录。单向散列无法解密(甚至不能解密加密它的人!)因此很难使用散列密码。

因为您无法解密数据库中的密码,所以您需要获取已输入的密码并重复相同的过程以对其进行哈希处理,然后比较散列值以查找匹配项。因此,你的盐实际上并不是完全随意的,因为你最终会得到不同的结果。

除此之外,您真的不希望以未加密的形式传输密码,这就是登录页面通常是HTTPS页面的原因。

答案 10 :(得分:-2)

“正确?”


如果您需要二进制答案:

 1