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

Zak*_*ria 120 passwords hash client-side

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

然而,我的一个朋友告诉我,一个"清晰"的密码可能会被网络软件嗅到.

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

Dir*_*irk 108

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

对于这个问题,更安全的身份验证协议通常会跳过许多箍,以确保这种重放攻击通常不会起作用,通常是允许客户端选择一堆随机位,这些位随密码一起被散列,并且还明确提交给服务器.

在服务器上:

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

在客户端:

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

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

编辑所有这一切都是容易出错和繁琐而且有点难以做到(阅读:安全).如果有可能,可以考虑使用已经被懂行的人写的认证协议的实现(不像我!以上仅仅是从一本书我前一段时间阅读的记忆.)你真的不想要这个自己平时写.

  • 需要明确的是:如果您不使用HTTPS,那么您在客户端上运行的javascript无关紧要; MITM可以在页面到达客户端之前修改其内容.**HTTPS是唯一的解决方案.** (12认同)
  • 然而,为了提交密码或密码的散列,通常使用像Diffie-Hellman这样的非对称过程来建立加密密钥,该加密密钥允许双方交换信息而不会使窥探方能够解密它.这正是SSL所做的,也是大多数网站在HTTPS/SSL上拥有登录页面的原因.SSL已经可以防止重放攻击.我建议利用SSL而不是构建自己的协议.虽然我同意salting + hashing密码客户端,但是通过已建立的SSL连接发送这些密码. (7认同)
  • 如果您将密码以散列形式存储在服务器上(如您所愿),那么客户端将需要对密码进行两次散列:首先,仅使用密码,因此它与服务器的世界视图相匹配,然后如上所述协议的缘故. (4认同)
  • @Dirk,既然攻击者可以嗅探两种方式,那么"随机位"就会被嗅到.然后攻击者可以离线分析(读取:暴力)请求和响应对以查找原始密码. (3认同)
  • 他如何使用登录系统中的哈希密码进行身份验证,因为它将再次进行哈希处理? (2认同)
  • 需要澄清的问题是:只有在密码存储在服务器端“不加盐”的情况下,才可以使用此模式,对吗?使用盐时,客户端将需要先知道盐,然后再用随机字节对密码进行哈希处理。并且允许客户端从服务器获取盐有安全风险吗?还是没有太大的风险(前提是我设法以某种方式为不存在的用户创建了永久性的假盐)? (2认同)
  • 请注意,尽管HTTPS可以很好地保护实时劫持,但它并不能抵抗对日志的攻击,无论是服务器端调试日志,还是大多数国家法律规定公司必须维护的“透明代理”日志。每当这些日志将被泄露时(无论是疏忽大意还是被要求进行法律调查),以明文形式发送密码都会暴露它们。 (2认同)

小智 57

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

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

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

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

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

但是,如果你真的不想购买证书,仍然要实现客户端javascript哈希(并使用standford库(SJCL),不要实施CRYPTO自己).

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

(SHA256(SHA256(password)+salt))
Run Code Online (Sandbox Code Playgroud)

(将盐保存为数据库中的明文)).并发送您的密码,如下所示:

RSA_With_Public_Key(SHA256(password))
Run Code Online (Sandbox Code Playgroud)

并检查您的密码,如下所示:

if SHA256(RSA_With_Private_Key(SHA256(sent_password))+salt_for_username) == stored_pass: login = ok
Run Code Online (Sandbox Code Playgroud)

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


dim*_*414 23

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

稍微好一些,因为它可以防止恶意用户知道密码是什么,但由于他们仍然可以登录(或可能重建原始密码),这没有那么有用.

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


编辑2014年8月: Google正在越来越强烈地推动网站在任何地方切换到HTTPS,因为保护通信本身是防止网络嗅探攻击的唯一方法.混淆传输数据的尝试只会阻碍而不是阻止专用攻击者,并且会给开发人员带来危险的虚假安全感.

  • 反馈是受欢迎的,无声的downvotes帮助没有人. (28认同)
  • 我认为,如果您*仅*专注于获取 `x` 用户的密码和访问单个服务,那么您认为客户端散列只是“稍微好一点”的观点是正确的。如果你考虑集体效应,我会说它“好多了”;因为它可以防止构建用于跨多个服务暴力破解加盐哈希的密码的大型查找数据库。海事组织。查看 AWS Cognito 在客户端中执行的操作以供参考。 (2认同)

Kid*_*rla 11

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

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

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

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

顺便说一下,这类问题可能会在Security StackExchange上得到更多专家的回应.

  • 完全同意这一点.对于客户端工作方法,人们还必须将盐送到客户端,这将使盐析的整个目的无效! (3认同)
  • @user1034912 是的,但我认为 OP 不仅仅想依赖 SSL 来保证安全。某些网络(尤其是企业网络)的 SSL 在某些负载均衡器处终止,这意味着明文密码对服务应用程序以外的网络组件可见。通常我们使用客户端加密来避免这种情况,并确保客户端和服务应用程序之间的端到端加密。 (3认同)
  • 显然,如果您在客户端对其进行散列,则必须在服务器端再次对其进行散列,以防止您提出的观点。但正如其他人指出的那样,为了保护隐私,您已经需要客户端加密。 (2认同)
  • 发送一次性公钥...这不是 SSL 的作用吗? (2认同)

Rap*_*ael 7

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

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

因此,散列/加密客户端是有道理的。

  • 同意!很多人都忽略了这一点。如果我下载您的加盐散列密码的密码数据库,并且我只能使用散列查找数据库破解其中一个,那么我很有可能可以破解所有这些密码。一旦我有了 50k 个原始密码,我现在就拥有了只在服务器上加密的 `n` 服务上的 `x` 用户的密钥。如果每个服务在离开客户端之前对密码进行唯一的哈希处理,那么跨服务密码的大型数据库就会变得非常非常小。检查您的 AWS 登录流量,看看他们做了什么。亲爱的华生,这很有可能。 (2认同)

Eri*_*gar 6

最近 GitHub 和 Twitter 都宣布将密码存储在内部日志中。我在 bug 报告和其他日志中无意中发生过这种情况,这些日志进入了 splunk 等。对于 twitter 来说,如果特朗普的密码在日志中,那么管理员“看到”可能会是一件大事,而对于其他网站来说,可能不会如此这是一件大事,因为管理员不会有太多用处。不管怎样,作为管理员,我们不喜欢看到密码。

所以问题是,为了安全起见,哈希是否应该在客户端进行,但是我们如何在密码最终被服务器端哈希和比较之前保护密码,这样它就不会以某种方式被记录。

加密并不是一个坏主意,因为开发人员至少必须跳过一些麻烦,如果您发现密码进入日志,您可以更改加密密钥,销毁原始数据,然后该数据就变得毫无用处。最好每晚轮换一下钥匙,这样可以大大减少窗户的数量。

您还可以对用户记录中的哈希值进行哈希处理。泄露的密码将是经过哈希处理的纯文本密码。服务器将存储散列的散列版本。当然,哈希值会成为密码,但除非您有过目不忘的记忆力,否则您不会记住 60 个字符的 bcyrpt。用用户名加盐。如果您可以在登录过程中收集有关用户的信息(同时不暴露用户记录的存在),您也可以使用它来创建一个无法在站点之间共享的更强大的哈希值。中间没有人能够在站点之间剪切和粘贴捕获的哈希值。

与未提交回服务器的 cookie 结合使用,您可能会发现一些东西。在第一个请求时,使用密钥向客户端提交 cookie,然后确保 cookie 不会返回到登录服务,这样它被记录的机会很小。将密钥存储在会话存储中,然后在登录后或会话过期时立即删除它......这需要 JWT 人员的状态,但也许只需使用 nosql 服务即可。

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

  • 正是我所关心的。如果服务器由于实施不当或恶意意图而意外登录,那么用户的其他帐户如果重复使用密码,则可能会受到损害。 (2认同)