代码之家  ›  专栏  ›  技术社区  ›  lmcarreiro

为什么owasp不建议在客户端和服务器上都使用bcrypt密码?

  •  5
  • lmcarreiro  · 技术社区  · 8 年前

    由于github和twitter最近的问题:

    我在想,为什么在客户机和服务器上都用bcrypt加密密码不是最佳实践?因为我不会改变任何已经是服务器端最佳实践的东西(salt、strong hash、https),所以它只能更安全。服务器将把已经散列的密码作为密码,并在存储之前再次散列它。

    • 如果我在引发异常时记录整个请求,如果登录/注册请求中发生异常,我将永远无法访问用户明文密码
    • 我知道,如果有人可以通过mitm(许多公司在其私有网络中用它替换ssl证书)或日志或恶意服务器管理员访问这些只有客户端散列的密码,他们将能够在我的站点中使用它进行身份验证,但不会有权访问明文密码,因此它永远不会损害用户在其他站点和服务中的帐户(即使是那些重用密码的用户)
    4 回复  |  直到 8 年前
        1
  •  1
  •   Dan    8 年前

    我想解决一个类似的问题,即可以在服务器上登录纯文本密码。结论是 您应该始终另外散列客户端密码 如果可以的话。

    以下是一些关于 客户端加服务器 散列:

    Client-Plus-Server Password Hashing as a Potential Way to Improve Security Against Brute Force Attacks without Overloading the Server

    Salted Password Hashing - Doing it Right

    具体见:

    在web应用程序中,总是在服务器上散列

    如果您正在编写一个web应用程序,您可能想知道在哪里散列。 如果用javascript在用户浏览器中散列密码, 或者应该发送到服务器“清除”并在那里散列?

    即使你用javascript散列用户密码,你仍然 必须散列服务器上的散列。考虑一个散列的网站 用户浏览器中的用户密码,而不在 服务器。若要验证用户,此网站将接受哈希 从浏览器中检查哈希值是否与 数据库。这似乎比在服务器上散列更安全, 因为用户的密码永远不会发送到服务器,但不会。

    问题是客户端哈希逻辑上成为用户的 密码。用户只需告诉服务器就可以进行身份验证 密码的散列。如果一个坏人得到了一个用户的散列,他们可以 使用它向服务器进行身份验证,而不知道用户的 密码!所以,如果那个坏蛋以某种方式窃取了散列数据 从这个假设的网站上,他们可以立即访问 每个人的账户都不用猜密码。

    这并不是说你不应该在浏览器中散列,但是如果你 是的,你当然也要在服务器上散列。散列 浏览器当然是个好主意,但请考虑以下几点 对于您的实现:

    客户端密码哈希不能替代https(ssl/tls)。如果浏览器和服务器之间的连接是 不安全,中间人可以修改javascript代码 下载以删除散列功能并获取用户的 密码。

    有些web浏览器不支持javascript,有些用户在浏览器中禁用javascript。为了获得最大的兼容性,你的应用程序 应该检测浏览器是否支持javascript和 如果没有,则在服务器上模拟客户端哈希。

    您还需要对客户端散列进行盐渍处理。显而易见的解决方案是让客户端脚本向服务器索取用户的盐。 别这么做,因为它可以让坏人检查用户名是否 在不知道密码的情况下有效。因为你在打盐 在服务器上也可以使用用户名(或者 电子邮件)与特定于站点的字符串(例如域名)连接为 客户端盐。

    经过研究,对客户机进行散列处理似乎也有明显的安全好处。如果通过https的密码被泄露,或者如果密码登录到服务器上,那么纯文本密码就不能很容易地在用户的其他帐户上重用(许多用户重用他们的密码)。

    唯一可能的缺点是客户端性能和服务器端密码验证。用户可以操作您的客户端js并提交一个“弱”密码。服务器知道得再好不过了。但我认为这是一个小问题,它依赖于人们故意修改他们的客户端代码,以削弱他们自己的安全性。

        2
  •  3
  •   martinstoeckli    8 年前

    客户端散列可以完成,但是我们应该考虑我们真正实现了什么。

    你可能 希望 要实现的是,当通过(希望是加密的ssl)连接发送密码时,攻击者无法读取该密码。如果攻击者能够拦截流量,则很有可能他也可以更改流量,因此可以删除任何执行客户端散列的javascript。然后整个保护来自服务器端哈希。

    你什么 可以 实现是,可以减少服务器的负载,因为您让客户端做了繁重的计算。如果可以保证客户端的完整性,那么可以在客户端上进行密钥拉伸,并在服务器上使用快速散列。对于已安装的应用程序,这可能是一个选项,但不建议用于网站,因为无法保证客户端的完整性,而且javascript通常速度较慢,因此可以减少查房次数。

    如果攻击者只能监听通信量,但不能更改它,那么您将得到一个小的好处。你愿意花在散列上的时间必须分为客户机部分和服务器部分(不能让用户永远等待)。服务器时间必须足够长,以保证安全性,这样在客户端上就没有多少时间了。如果在客户机上使用过快的散列,则截获的密码散列仍在暴力强制的范围内(尽管 一个攻击者必须跨过的障碍)。

    所以简而言之,这通常是不值得的麻烦,优势太小,时间最好投资在服务器上的散列时间。

        3
  •  1
  •   Omer Levi Hevroni    8 年前

    任何散列(包括 bcrypt )需要秘密阅读 here 更多细节。如果该salt丢失,客户端将无法创建相同的散列,这与丢失密码相同。因此,您需要创建一个机制,允许所有客户机安全地获取盐。你需要确保黑客不会得到这些盐。这很难实现。

    另一个需要考虑的问题是终端用户设备的限制——例如,android设备的cpu相当弱,并且远不如一般服务器的强大。作为 BCRIPT 是计算散列所需的时间,您需要选择参数,以便一个好的服务器(甚至可能使用gpu)能够在很慢的时间内计算散列(例如,对于20个字符的密码,>1s)。这使得创建彩虹表非常困难。

    因此,除非你能保证你的所有用户都在足够强大的设备上运行,否则不建议你这样做 BCRIPT 在客户端。

        4
  •  -2
  •   The Spooniest    8 年前

    此方案的问题在于它要求服务器信任客户端 . 特别是,它假设客户机将始终实际散列用户键入的内容。如果我们像入侵者那样打破这个假设,问题就会出现。

    bob从您的服务器日志中有一个(单哈希)密码列表。这些不是明文密码,但不是密码文件中的双哈希密码。但是假设他对您的客户机做了一个小小的更改:他取出bcrypt()行,这样它就不再散列他在发送之前粘贴到password字段中的内容:相反,它只发送原始文本。

    然后他开始发送登录信息。现在您的服务器可以看到用户名和单哈希密码(因为这是bob键入的,因为这是bob知道的)。它假设这是通常的客户机,所以它会再次散列密码,并检查其文件中的双重散列密码…而且它被精确地散列了两次,所以匹配。鲍勃不知道明文密码,但通过修改客户端,他做到了,所以他不知道 需要 知道它。