Php 我应该为密码存储哈希吗?
用户系统和密码:我在浏览MD5的内容,我想知道密码的正常/良好做法是什么。现在,我认为人们会对密码进行超级加密并存储哈希值。如果是,密码检查是如何工作的?我只是让输入的密码再次经过加密过程,然后用存储的密码检查散列,对吗 这个问题可能与上述问题相矛盾,但我的salt是否应该是随机生成的值?如果有,什么时候有用 编辑:在用户系统中,除了密码之外,还有什么应该加密的好方法?他们加密用户名还是其他什么Php 我应该为密码存储哈希吗?,php,encryption,passwords,Php,Encryption,Passwords,用户系统和密码:我在浏览MD5的内容,我想知道密码的正常/良好做法是什么。现在,我认为人们会对密码进行超级加密并存储哈希值。如果是,密码检查是如何工作的?我只是让输入的密码再次经过加密过程,然后用存储的密码检查散列,对吗 这个问题可能与上述问题相矛盾,但我的salt是否应该是随机生成的值?如果有,什么时候有用 编辑:在用户系统中,除了密码之外,还有什么应该加密的好方法?他们加密用户名还是其他什么 第二次编辑:什么是单向散列?我的意思是,从技术上讲,我不能对我的源代码进行反向工程吗?也许这是个糟糕
第二次编辑:什么是单向散列?我的意思是,从技术上讲,我不能对我的源代码进行反向工程吗?也许这是个糟糕的问题,因为我对单向散列不太了解。永远不要以可逆的方式存储密码,始终使用单向散列。检查通过对输入的密码进行哈希运算并将两个哈希值相互检查来工作。“正确吗?”
如果您需要二进制答案:
1
您应该存储一个密码的散列,而不是实际的可读字符串,也可以考虑使用“盐析”来增加额外的安全性
首先创建一个盐。 注意:示例是用PHP编写的 然后输入密码// 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
的“散列”。请注意,如果不知道哈希函数如何工作,则无法从300
派生30
这是一个非常简单的“散列”,如果你知道它总是乘以10,那么你可以很容易地将其反转。这要复杂得多。这不能简单地逆转
您会发现,除了密码散列之外,几乎没有其他内容,也没有任何内容是加密的。加密数据库会带来巨大的开销
我想您可以对用户名应用类似的salt/hash模式,但这样会有陷阱。如果您想在代码中的某个地方使用该用户名,该怎么办?如果您想检查以确保它是表中唯一的,该怎么办
第二次编辑:什么是单向散列?我
我的意思是,从技术上讲,我不能逆转吗
设计我的源代码?也许这是
一个糟糕的问题,因为我不知道
关于单向散列有很多
见上文()。单向散列就是这样。单向映射<代码>A=>B没有其他内容<代码>B!=>A和A
只能是B
有人提到了异或操作的性能。虽然我觉得性能在很大程度上可以忽略不计,但我还是进行了一次快速测试
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";
密码的标准做法是不将原始密码存储在任何地方。Unix密码过去是用“crypt”加密的,它会使用随机密码。salt本身存储在加密密码的前两个字符中。当用户输入密码时,系统将使用加密密码的两个字符作为salt来加密输入的密码,如果加密结果与存储的加密密码相同,则为匹配。使用MD5密码也可以做类似的事情 这就是为什么好的网站永远不会通过电子邮件向你发送密码,而是将你的密码重置为一次性值——因为他们不知道你的密码 对此进行一点扩展:MD5散列是一个单向函数——如果对同一个值进行散列,则得到的是同一个散列,但不能接受散列并以某种方式将其转换为值。两个值产生相同散列的可能性很小但有限(初始字符串越大或散列越小,可能性越高),但他们选择散列算法使人们选择作为密码的两个字符串散列到相同值的可能性几乎为无穷小。你可以把单向散列想象成绞肉机——你可以看着从绞肉机里出来的肉,看看是牛、羊还是猪,但你不能通过另一条路把它弄回来
因此,没有人可以恢复您的密码,因为它从未存储在他们系统的任何位置,只是它的散列。此主题有许多变体 有关详细信息,请阅读以下内容: 然后读一读: 一般来说:您只存储摘要。从来没有密码 在RFC2617之后,您应该存储用户名、域和密码的摘要 客户端(“代理”)获取用户名、密码、领域等,并创建摘要,并将其发送到服务器 您的服务器根据用户名查找其摘要版本 如果他们的摘要==保存在服务器中的摘要,则表示您同意密码(以及其他所有内容) 如果他们的消化如果摘要保存在服务器中,则您不同意密码(或其他内容)。这意味着他们没有正确地获取领域或用户名,或者他们没有正确地获取nonce,或者出现了其他问题。他们不可信
完整的RFC2617包含用于计算其他内容摘要的其他数据和密码摘要,以绝对确保客户端正在进行响应。存储哈希密码的原因是,如果有人设法获取了密码
$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";
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