是否值得在客户端散列密码

时间:2010-09-15 08:32:39

标签: passwords client-side hash

当我想建立登录系统时,我总是将给定密码的MD5与服务器端用户表中的值进行比较。

然而,我的一位朋友告诉我,网络软件可能会嗅到“清晰”的密码。

所以我的问题是:在客户端散列密码是个好主意吗?它比在服务器端散列更好吗?

11 个答案:

答案 0 :(得分:101)

基本上,你的朋友是对的。但是,简单地在客户端散列密码只比 更好,而不是将其作为纯文本提交给服务器。能够收听您的纯文本密码的人当然也能够收听散列密码,并使用这些捕获的哈希来对您的服务器进行身份验证。

对于这个问题,更安全的身份验证协议通常会跳过一些箍,以确保通常允许客户端选择一堆随机位,这样的重放攻击无法正常工作用密码,也可以清楚地提交给服务器。

在服务器上:

  • 生成一些随机的
  • 将这些位(以明文形式)发送到客户端

在客户端:

  • 生成一些随机位
  • 连接密码,服务器的随机位和客户端随机位
  • 生成上述
  • 的哈希值
  • 提交随机数据(以明文形式)和哈希值到服务器

由于服务器知道自己的随机信息以及客户端的随机位(它将它们作为明文),它可以执行基本相同的转换。该协议确保在此对话中的任何人都可以使用该信息稍后使用所记录的信息进行错误验证(除非使用非常弱的算法......),只要双方每次都生成不同的“噪声位”,进行握手。

编辑所有这些都容易出错并且单调乏味且难以理解(阅读:安全)。如果可能的话,考虑使用已经由知识渊博的人编写的身份验证协议实现(与我不同!以上仅仅是我之前读过的一本书的记忆。)你真的不想自己写这个。

答案 1 :(得分:57)

首先, NOT 可以提高应用程序的安全性(假设它是一个webapp)。

使用SSL (或者实际上是TLS,通常称为SSL),它并不是真的很贵(衡量你用它来寻找解决方法并将其乘以最低工资的时间,购买证书几乎总能获胜) )。

为什么这很简单。 TLS解决了一个问题(当与购买的证书一起使用,而非自签名时)在密码学方面相当大:我如何知道我正在与之交谈的服务器是我认为我正在与之交谈的服务器? TLS证书是一种说法:“我,您的浏览器信任的证书颁发机构,证明[url]上的网站有这个公钥,带有相应的私钥,只有服务器知道的(私钥),看看我在整个文档上签了我的签名,如果有人改了你就可以看到“。

没有TLS,任何加密都变得毫无意义,因为如果我坐在你旁边的咖啡店,我可以让你的笔记本电脑/智能手机认为我是服务器和MiTM(中间人)你。使用TLS,您的笔记本电脑/智能手机会尖叫“UNTRUSTED CONNECTION”,因为我没有与您的网站匹配的证书颁发机构签名证书。 (加密与身份验证)。

免责声明:用户倾向于点击这些警告:“不受信任的连接?什么?我只想要我的小猫照片!添加例外 点击 确认< / em> 点击 YAY!小猫!“

但是,如果您真的不想购买证书,仍然实施客户端javascript哈希(并使用Standford库(SJCL),永远不要实施CRYPTO自己< /强>)。

为什么呢?密码重用!我可以在没有HTTPS的情况下窃取您的会话cookie(这允许我假装您的服务器,我是你)(参见firesheep)。但是,如果你在登录页面添加一个javascript,在发送之前,哈希你的密码(使用SHA256,甚至更好,使用SHA256,向他们发送你生成的公钥,然后加密密码,你不能使用盐用此),然后将散列/加密的密码发送到服务器。 使用salt刷新服务器上的哈希并将其与存储在数据库中的哈希值进行比较(存储密码如下:

(SHA256(SHA256(password)+salt))

(将盐保存为数据库中的明文))。并发送您的密码:

RSA_With_Public_Key(SHA256(password))

并检查您的密码:

if SHA256(RSA_With_Private_Key(SHA256(sent_password))+salt_for_username) == stored_pass: login = ok

因为 IF 有人嗅探您的客户,他们将能够作为您的客户端登录(会话劫持),但他们将从不查看明文密码(除非他们然而,改变你的javascript,星巴克黑客可能不会知道如何/对此感兴趣。)因此他们将获得访问您的webapp,但不能访问他们的电子邮件/ Facebook /等。 (您的用户可能会使用相同的密码)。 (电子邮件地址将是他们的登录名,或者将在他们的webapp上的个人资料/设置中找到)。

答案 2 :(得分:21)

你可能不会担心这一点 - 正如Dirk所提到的那样,即使您在网络上散列恶意用户的密码并看到散列被发送,也可以简单地自己发送相同的散列。

稍微更好,因为它可以防止恶意用户知道密码是什么,但由于他们仍然可以登录(或可能reconstruct the original password),这没有用

通常,如果您担心用户的密码和数据的安全性(并且您应该这样做!),您将需要使用安全的SSL服务器。如果出于某种原因这不是你的问题,你也可以不去烦恼;它只是security through obscurity


编辑2014年8月: Google正在越来越强烈地将网站推向switch to HTTPS everywhere,因为保护通信本身是防止网络嗅探攻击的唯一方法。试图模糊传输的数据只会阻碍而不是阻止专门的攻击者,并且会给开发人员带来危险的虚假安全感。

答案 3 :(得分:8)

实际上我不同意在这种情况下客户端散列更安全。我认为这不太安全。

在数据库中存储密码哈希而不是真实密码(甚至是加密密码)的全部意义在于,在数学上不可能从哈希中获取原始密码(尽管理论上可以获得冲突哈希输入,其难度取决于哈希算法的安全强度)。这里可能的攻击媒介是,如果潜在的攻击者以某种方式破坏了您的密码存储数据库,他/她仍然无法获取您的用户的原始密码。

如果您的身份验证机制发送密码哈希值,那么在此安全漏洞情况下,攻击者无需知道真实密码 - 他们只是发送他们拥有的哈希值而且他们可以访问特定密码用户的帐户,以及扩展名,整个系统。这完全违背了存储散列密码的要点!

真正安全的方法是向客户端发送一次性公钥,以便加密密码,然后在服务器端解密并重新哈希。

顺便说一句,这类问题可能会在Security StackExchange上获得更多专家回复。

答案 4 :(得分:3)

这取决于你可以使用客户端哈希,但服务器端盐是不可能的。

看一下链接 Password encryption at client side

答案 5 :(得分:2)

最近GitHub和Twitter都宣布密码存储在内部日志中。我已经无意中发生了错误报告和其他日志,这些日志已经进入splunk等等。对于Twitter,如果特朗普的密码在那里日志,对于管理员“看到”可能是一个大问题,对于其他网站可能不是由于管理员对它没有多大用处,所以大不了一笔。无论管理员如何,我们都不喜欢看密码。

所以问题是如果哈希应该在客户端发生安全性,但是如何在最终被密码进行哈希并在服务器端进行比较之前保护密码,这样它就不会以某种方式记录。

加密并不是一个坏主意,因为开发人员至少必须跳过一些箍,如果你发现密码进入日志,你只需更改加密密钥,破坏原始密码,数据就变得无用了。更好的是每晚旋转按键,它可以大大减少窗户。

您还可以在用户记录中散列哈希值。泄露的密码将是纯文本密码。服务器将存储哈希的哈希版本。确定哈希成为密码,但除非你有一个摄影记忆,否则你不会记得一个60 char bcyrpt。使用用户名加盐。如果您可以在登录过程中收集有关用户的信息(虽然不公开用户记录存在),您可以使用它,并创建一个无法在站点之间共享的更健壮的哈希。中间没有人能够在网站之间剪切和粘贴捕获的哈希值。

与未提交回服务器的cookie结合使用,您可能会遇到某些问题。在第一次请求时,使用密钥向客户端提交cookie,然后确保cookie不会返回登录服务,因此很少有机会记录它。将密钥存储在会话存储中,然后在登录发生后或会话过期时立即将其删除...这需要JWT的状态,但可能只是使用nosql服务。

因此,管理员会在splunk或bug报告工具中遇到其中一个哈希和加密密码。对他们来说应该没用,因为他们再也找不到加密密钥,即使他们这样做了,他们也必须暴力破解哈希。此外,最终用户没有沿线发送任何明文,因此中间的任何人至少有更难的时间,你不能只是跳到另一个站点并登录。

答案 6 :(得分:1)

我最近在这方面做了很多工作,IRL有两个问题,客户端散列/ 对称加密真的杀了这个想法: 1.你必须将盐恢复到服务器SOMEHOW ...并加密它客户端你需要一个密码......这会破坏目的。 2.你暴露你的哈希实现(不是一个巨大的交易,因为大多数站点使用3或4个哈希算法中的一个)这使得攻击更容易(因为只需要尝试一个而不是n)。

我最终使用的是OpenPGP.js或类似的客户端上的非对称加密... 这依赖于客户端上导入的或客户端生成的密钥以及发送它的公钥的服务器。只有客户端的公钥可以发送回服务器。 这可以防止MIM攻击,并且与设备一样安全(我目前默认在localStore中存储客户端的私钥,这是一个演示)。

这样做的主要优点是我永远不必将用户数据存储在我的服务器/数据存储中未加密的存储器中(并且我的服务器的私钥在物理上是分开的)

这样做的基础是为人们提供一种在HTTPS受到限制的情况下安全通信的方式(例如,伊朗/朝鲜国家...),这也只是一个有趣的实验。

我是第一个想到这个的人,http://www.mailvelope.com/使用这个

答案 7 :(得分:1)

如果有人可以在您的连接上看到数据,那么身份验证将无法保存您。 相反,我会做超级秘密的事情。

在发送到服务器之前在客户端预先传输的密码。 (服务器存储从浏览器发送的该哈希的另一个哈希值和盐值)。

因此,中间人攻击可以允许他们发送相同的哈希值来登录,但用户密码将不知道。这将阻止他们尝试使用相同凭据的其他服务登录其他地方。

用户数据也在浏览器端加密。

啊,所以中间人攻击会获得加密数据,但如果没有用于登录的实际密码则无法解密。 (用户密码在登录时存储在浏览器的DOM中)。 所以真正的用户会看到解密的内容,但中间人不能。 这也意味着任何NSA或其他机构都无法要求您/公司/托管服务提供商解密这些数据,因为他们也不可能这样做。

这两种方法的一些小例子都在我的博客上 http://glynrob.com/javascript/client-side-hashing-and-encryption/

答案 8 :(得分:1)

请注意,保护密码不受第三方侵害并不是全部。

一旦涉及到隐私(这些天是什么时候呢?)不想知道密码。您不能滥用或泄漏自己所没有的,因此,即使您从未见过他们的明文密码,您和您的客户也可以睡得更好。

因此,对客户端进行哈希/加密很有意义。

答案 9 :(得分:0)

考虑一下: -

客户端向服务器发送请求“我有一个密码来验证”。

服务器向客户端发送一次性随机字符串。 R $

客户端将用户密码嵌入此字符串中(基于您希望应用的任何(变量)规则。)

客户端将字符串发送到服务器,如果密码正常,则服务器将用户登录。

如果服务器使用R $接收另一个登录请求,则用户将被注销,并且该帐户将被冻结等待调查。

显然,将采取所有其他(正常)安全预防措施。

答案 10 :(得分:0)

这种客户端哈希的想法是为了保护用户,而不是您的站点。正如已经多次提到的,纯文本或哈希密码都可以平等地访问您的网站。您没有安全保障。

但是您的用户实际的纯文本密码只能由他们知道。知道他们选择的密码是可以在其他站点和系统上针对他们使用的信息。通过防止服务器开发人员或第三方发现他们的密码选择,您可以成为以客户为中心的网站。