有人告诉我,您不应该将用户密码存储在数据库中,但是如果我无法保存用户密码,我该如何验证用户身份?只是对它们进行加密就足以保证它们的安全吗?
最近新闻中有几篇关于高知名度网站遭到入侵的报道,例如 LinkedIn,我认为这样高知名度的网站不会存储纯文本密码,因此假设它们是加密的。
免责声明:我最初在 Quora 上发布了这个,但觉得答案更适合 Stack Overflow。
用于存储和检查用户密码而不实际保留密码的方法是将用户输入与存储的哈希值进行比较。
什么是哈希?
散列是通过一种算法传递可变长度的数据(小密码、大密码、二进制文件等)的过程,该算法将其作为一组固定长度的数据返回,称为散列值。哈希仅以一种方式起作用。一个由几 Mb 组成的 *.img 文件可以像密码一样进行哈希处理。(实际上,在大文件上使用散列来检查它们的完整性是一种常见的做法;假设您使用 bittorrent 下载了一个文件,当它完成时,软件会对其进行散列并将您拥有的散列与您应该使用的散列进行比较有,如果它们匹配,则下载未损坏)。
带有哈希的身份验证如何工作?
当用户注册时,他会给出一个密码,pass123
然后将其散列(通过任何可用的散列算法:sha1、sha256 等,在这种情况下为 md5)到该值32250170a0dca92d53ec9624f336ca24
,并且该值存储在数据库中。每次您尝试登录时,系统都会实时对您的密码进行哈希处理,并将其与存储的哈希值进行比较,如果匹配,您就可以开始了。您可以在这里尝试在线 md5 哈希:http: //md5-hash-online.waraxe.us/
如果两个哈希值相同怎么办?用户可以使用不同的通行证登录吗?
他可以!那就是所谓的碰撞。假设在一个虚构的散列算法上,值pass123
会产生散列ec9624
并且值pass321
会产生完全相同的散列,那么散列算法就会被破坏。由于发现了冲突,常见的算法 md5 和 sha1(LinkedIn 使用的那个)都被破坏了。被打破并不一定意味着它不安全。
如何利用碰撞?
如果您可以生成哈希,则与您可以将该站点标识为用户的用户密码生成的哈希相同。
彩虹桌攻击。
破解者很快就明白,一旦他们捕获了散列密码表,逐个利用密码是不可行的,因此他们设计了一种新的攻击向量。他们将生成存在的每一个密码(aaa、aab、aac、aad 等)并将所有哈希值存储在数据库中。然后他们只需要使用所有顺序生成的哈希(亚秒级查询)在数据库中搜索被盗的哈希并获得相应的密码。
盐来拯救(LinkedIn 失败的地方!)
安全性是由破解者破解您的密码所需的时间以及您更改密码的频率来定义的。彩虹桌的安全性下降得非常快,所以业界想出了盐。如果每个密码都有一个独特的转折点怎么办?那是盐!对于每个注册的用户,您都会生成一个随机字符串,比如 3 个字符(业界建议使用 16 个字符 - https://stackoverflow.com/a/18419 ......)。然后将用户密码与随机字符串连接起来。
password - salt - sha1 hash
qwerty - 123 - 5cec175b165e3d5e62c9e13ce848ef6feac81bff
qwerty - 321 - b8b92ab870c50ce5fc59571dc0c77f9a4a90323c
qazwsx - abc - c6aec64efe2a25c6bc35aeea2aafb2e86ac96a0c
qazwsx - cba - 31e42c24f71dc5a453b2635e6ec57eadf03090fd
正如你所看到的,完全相同的密码,给定不同的盐值,生成完全不同的哈希值。这就是 salt 的目的,也是 LinkedIn 失败的原因。请注意,在表上您只会存储哈希和盐!永远不要密码!
拿到 LinkedIn 哈希值的人做的第一件事就是对哈希值进行排序,看看是否有匹配项(这是因为多个用户有相同的密码——真可惜!)这些用户是第一个放弃的。如果通行证表被加盐......这一切都不会发生,他们将需要大量的时间(和计算机资源)来破解每一个密码。这样一来,LinkedIn 就有足够的时间来实施新的密码政策。
希望答案的技术方面能够深入了解身份验证的工作原理(或应该如何工作)。
真的很喜欢,当有人问这个问题时,因为有人想做得更好。只知道几个重点,即使是知名网站也可以避免很多麻烦。
最近我写了一篇关于哈希密码的教程,它使用了一种希望简单易懂的语言。它允许使用 SQL 注入,解释盐和胡椒的用法,并指出需要慢速密钥派生函数。