是否值得在客户端哈希密码


132

当我要放置一个登录系统时,我总是将给定密码的MD5与服务器端的users表中的值进行比较。

但是,我的一个朋友告诉我,网络软件可能会嗅到“清除”密码。

所以我的问题是:在客户端哈希密码是否是一个好主意?它比在服务器端对其进行哈希处理更好吗?


1
我当时正在考虑在客户端对哈希密码进行哈希处理,但只是为了确保我可以放心,客户端的密码在服务器端永远不会以明文形式存在,这意味着知道我不知道其实际密码后,他们会感到很轻松,或者如果妥协,就不能轻易放弃。我疯了吗?
飓风

1
出于完整性考虑,因为我们正在谈论安全性,并且OP中提到了MD5:在加密密码时,应始终使用盐。 使用无盐的普通MD5刚好比在数据库中存储纯文本密码好。
sffc

1
@Cyclone Hashing仅在客户端绝对是一个坏主意,因为如果攻击者以某种方式知道哈希,则可以绕过客户端哈希代码使用密码登录,就好像他知道密码一样。
Teejay '16

5
@Teejay:这就是为什么您不以明文形式发送哈希的原因。服务器向客户端发送随机盐,您添加密码哈希,然后再次对整个哈希进行哈希,然后将其发送回服务器,服务器进行相同的计算。重播攻击失败,因为
注解

2
这个问题不应该在security.stackexchange.com上解决吗?
efr4k '16

Answers:


115

基本上,您的朋友是对的。但是,简单地散列在客户端的密码只刚刚超过其提交的纯文本服务器更好。可以侦听您的纯文本密码的人当然也可以侦听哈希密码,并使用自己捕获的这些哈希值对您的服务器进行身份验证。

为此,通常通过允许客户端选择一堆随机位(随密码一起散列),以确保更可靠的身份验证协议通常无法跳过,从而确保这种重播攻击不起作用。 ,并且还明确地提交给服务器。

在服务器上:

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

在客户端上:

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

由于服务器知道自己的随机信息以及客户端的随机位(以明文形式获取它们),因此它可以执行基本相同的转换。该协议可确保,只要双方双方每次均产生不同的“噪声位”,那么在此对话中收听的任何人都无法稍后使用该信息来对记录的信息进行错误的身份验证(除非使用了非常弱的算法...),握手。

编辑所有这些都是容易出错和乏味的,并且很难正确处理(阅读:安全)。如果可能,请考虑使用已经由博学多才的人编写的身份验证协议实现(与我不同!上面的内容仅是我一段时间前读过的一本书的记忆。)您真的不想通常自己写这个。


5
由于将再次对哈希密码进行哈希处理,他如何在登录系统中使用哈希密码进行身份验证?
Zakaria 2010年

4
如果您将密码以散列形式存储在服务器上(如应有的话),则客户端将必须对密码进行两次散列:首先,单独输入密码,使其与服务器的世界观相匹配,然后如上所述该协议的缘故。
德克2010年

3
@Dirk,由于攻击者可以同时嗅探两种方式,因此将嗅探“随机位”。然后,攻击者可以离线分析(读取:蛮力)请求和响应对以查找原始密码。
Pacerier

7
但是,出于提交密码或密码哈希的目的,通常使用诸如Diffie-Hellman之类的非对称过程来建立加密密钥,该加密密钥允许双方交换信息而没有监听方能够解密信息。这正是SSL的作用,也是大多数站点在HTTPS / SSL上都有其登录页面的原因。SSL已经可以防止重放攻击。我建议使用SSL而不是构建自己的协议。尽管我确实同意对客户端进行盐析+哈希处理,但是可以通过已建立的SSL连接发送这些密码。
AaronLS

14
需要明确的是:如果您不使用HTTPS,则在客户端上运行什么javascript都没有关系。MITM可以在您的页面到达客户端之前对其进行修改。HTTPS是唯一的解决方案。
艾丹,2015年

60

首先,这样做提高应用程序的安全性(假设它是一个Web应用程序)。

使用SSL(或实际上称为TLS,通常称为SSL),它并不昂贵(测量找到它的方法并用最低工资乘以它的时间,购买证书几乎总是会赢)。

为什么这样做很简单。TLS解决了一个在密码学上相当大的问题(当与购买的证书一起使用时,而不是自签名):我怎么知道我正在与之交谈的服务器就是我认为与之交谈的服务器?TLS证书是一种表达方式:“我,您的浏览器信任的证书颁发机构,证明[url]上的网站具有此公钥以及相应的私钥,只有服务器知道该私钥,我在整个文档上签名,如果有人对其进行了更改,您可以看到”。

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

免责声明:用户倾向于通过以下警告右击:“不可信的连接?是什么?我只想要我的小猫的照片!添加例外 单击“ 确认”, 单击确定!小猫!”。

但是,如果您真的不想购买证书,请仍然执行客户端javascript哈希(并使用standford库(SJCL),永远不要实现自己的加密)。

为什么?密码重用!我可以轻松地窃取您的会话cookie(这使我可以假装成您的服务器)而无需HTTPS(请参阅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

因为,如果有人在监听您的客户端,他们将能够以您的客户端身份登录(会话劫持),但他们永远不会看到纯文本密码(除非他们更改了您的JavaScript,但是,星巴克黑客可能不会知道如何做/感兴趣)这样,他们就可以访问您的Web应用,但不能访问他们的email / facebook / etc。(您的用户可能会使用相同的密码)。(电子邮件地址可以是他们的登录名,也可以在您的Web应用程序的个人资料/设置中找到)。


我认为这是一个很好的答案,但它可能需要更多有关如何正确添加盐的信息,最好在将密码存储在服务器(如bcrypt)上之前使用“慢速”哈希函数。
Neyt

24

您可能不必担心这一点-正如Dirk所述,即使您对密码进行哈希处理,恶意用户也可能会在网络上看到哈希发送,并且可以自己发送相同的哈希。

这是好,因为它可以防止恶意用户知道密码是什么,但因为他们仍然可以登录(或潜在重构原始密码),这是不是有帮助。

通常,如果您担心用户密码和数据的安全性(应该注意!),则需要使用安全的SSL服务器。如果无论出于何种原因您都不必担心,则最好不要去理会哈希。只是默默无闻安全感


2014年8月修改: Google越来越强烈地要求网站在任何地方都切换到HTTPS,因为保护通信本身是防止网络嗅探攻击的唯一方法。试图混淆传输的数据只会阻碍而不是阻止专门的攻击者,并且可能给开发人员带来危险的错误安全感。


我认为,如果您专注于获取x用户密码和访问单个服务,那么您的观点就是客户端哈希只会“稍微好一点” 。如果考虑集体效应,我会说这是“好得多”。因为它阻止建立用于在多个服务之间强行加盐哈希的密码的大型查询数据库。海事组织。请参阅AWS Cognito在客户端中执行的操作以供参考。
f1lt3r

17

实际上,我不同意客户端哈希在这种情况下更安全。我认为它不太安全。

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

如果您的身份验证机制发送了密码的哈希值,那么在这种安全漏洞情况下,攻击者无需知道真实的密码-他们只需发送自己拥有的哈希值即可,并且可以访问特定用户的帐户,进而扩展您的整个系统。这完全解决了首先存储哈希密码的问题!

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

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


3
完全同意这一点。对于客户端的工作方法,还必须将盐发送给客户端,这将使整个盐腌的目的无效!
詹姆斯·赖特

@JamesWright:重点是每次使用都会随机发送盐,这可以防止非法重用登录消息。(一种重放攻击形式)。每次发送相同的盐确实是没有意义的。
MSalters

您需要做的是使用“ nonce”(en.wikipedia.org/wiki/Cryptographic_nonce)。这样,服务器还可以控制盐并确保其安全性。在客户端进行哈希处理也很重要,这样注入的JS代码以后就很难找到。此处更多信息:stackoverflow.com/a/21716654/43615
Thomas Tempelmann,

有关在登录身份验证过程中使用salt + nonce的信息,请参见以下答案:stackoverflow.com/a/24978909/43615
Thomas Tempelmann,

显然,如果在客户端对它进行哈希处理,则必须在服务器端再次对其进行哈希处理,以防止出现问题。但是,正如其他人指出的那样,为了保护隐私,您已经需要客户端加密。
Daniel Methner

5

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

一旦涉及到隐私(这些天是什么时候(不是)?),不想知道密码。你不能滥用或泄露你没有什么,所以你和你的客户可以睡得更好,如果你从来没有看到他们的明文密码。

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


同意!很多人都错过了这一点。如果我下载了盐腌的哈希密码的密码数据库,并且可以使用哈希查找数据库破解一个密码,那么我可能会全部破解它们。一旦有了50k原始密码,我现在就拥有了仅在服务器上加密的服务上的x用户密钥n。如果每个服务在离开客户端之前都唯一地对密码进行哈希处理,那么跨服务密码的大型数据库将变得小得多。检查您的AWS登录流量,查看其作用。我亲爱的沃森,很有可能。
f1lt3r


1

我最近在这方面做了很多工作,IRL客户端散列/ 对称加密有两个问题,但确实扼杀了这个想法:1.您必须将盐返还给服务器SOMEHOW ...并进行加密在客户端,您将需要密码...这会达到目的。2.您公开了散列实现(这不是一个巨大的交易,因为大多数站点使用3或4个散列算法之一),这使攻击更容易(因为只需要尝试一个而不是n)即可。

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

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

这样做的基础是为人们提供一种在HTTPS受到限制的地方(例如伊朗/北朝鲜)等进行安全通信的方法,并且这只是一个有趣的实验。

我是最早想到这个的FAR,http://www.mailvelope.com/使用它


1

如果有人可以看到您连接上的数据,那么身份验证将无法保存您。相反,我将针对超级机密内容执行以下操作。

密码在发送到服务器之前会先在客户端进行伪装。(服务器存储从浏览器发送的该哈希值的另一个哈希值和加盐值)。

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

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

嗯,所以中间人攻击将获得加密的数据,但是如果没有用于登录的实际密码,就无法解密该数据。(用户登录时存储在浏览器中DOM中的用户密码)。因此,真实用户将看到解密的内容,而中间人则看不到。这也意味着任何国家安全局或其他机构将无法请求您/公司/托管提供商解密此数据,因为它们也将无法解密。

我的博客http://glynrob.com/javascript/client-side-hashing-and-encryption/中有这两种方法的一些小示例。


1

最近,GitHub和Twitter都宣布将密码存储在内部日志中。我已经在错误报告和其他日志中无意间发生了这种情况,这些日志已经进入splunk等。对于Twitter,如果特朗普的密码在该日志中,对于管理员来说“看”可能是一件大事,而对于其他网站则可能不是这很重要,因为管理员不会有太多用处。不管是管理员,我们都不希望看到密码。

因此,问题实际上是,散列是否应该在客户端进行以确保安全性,但是我们如何才能在密码最终被散列并由服务器端进行比较之前保护密码,以免以某种方式记录该密码。

加密不是一个坏主意,因为开发人员至少必须跳过一些麻烦,而且如果您发现密码进入了日志,则只需更改加密密钥,销毁原始密钥,数据就变得无用。最好还是每晚旋转一次按键,这样可以大大减少窗户。

您还可以在用户记录中对哈希值进行哈希处理。泄漏的密码将是哈希纯文本密码。服务器将存储哈希的哈希版本。当然,哈希值已成为密码,但是除非您有照片存储空间,否则您将不会记住60字符的bcyrpt。盐与用户名。如果您可以在登录过程中收集有关用户的一些信息(而不会暴露用户记录的存在),则可以添加一些内容,同时创建一个更健壮的哈希,无法在站点之间共享。中间没有人能够在站点之间剪切和粘贴捕获的哈希。

与无法提交回服务器的cookie结合使用,您可能会遇到麻烦。第一次请求时,请使用密钥将cookie提交给客户端,然后确保cookie不会返回登录服务,以免被记录。将密钥存储在会话存储区中,然后在登录发生或会话过期时立即将其删除...这需要JWT家伙使用状态,但可能仅使用nosql服务。

因此,管理员在splunk或错误报告工具中遇到了这些哈希密码和加密密码之一。对于他们来说,这应该是没有用的,因为他们再也找不到加密密钥了,即使他们找到了加密密钥,也必须蛮力地哈希。另外,最终用户没有沿线发送任何明文,因此中间的任何人至少都很难过,并且您不能只是跳到另一个站点并登录。


完全是我的关注。如果服务器由于实施不佳或恶意而意外登录,则如果用户重用密码,则其他用户帐户可能会受到损害。
丹丹

0

考虑一下:

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

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

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

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

如果服务器收到使用R $的另一个登录请求,则用户将注销并且帐户将被冻结以进行调查。

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


0

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.