【问题标题】:PHP Security - Checking users account when the hashed password is brokenPHP 安全性 - 当散列密码被破坏时检查用户帐户
【发布时间】:2014-02-20 23:17:48
【问题描述】:

目前我只是在玩 PHP,但我遇到了一个我想扩展的想法,并且需要知道它在您看来有多安全,以及我如何改进它以使其在实际使用中可以接受。

这就是我在数据库中存储密码的方式:

纯文本密码 -> 哈希密码(我使用漩涡,但任何方法实际上都可以)-> 随机/打乱哈希密码(使用 str_shuffle() 函数)。

我像这样将用户密码存储在数据库中,以确保如果数据库受到破坏,攻击者将无法在数据库中反转被破坏的密码哈希。 (因为从某种意义上说,您如何反转曾经是散列的随机文本?-尽管我确信您可以通过比较共享相同字符的散列列表来创建可能性列表。)

我检查他们在登录表单中输入的用户密码是否正确(与数据库中损坏的哈希相比)的方法是计算两个字符串/密码中的单个字母+数字(af & 0-9),看看它们是否匹配,如果匹配,我假设它们已正确登录。

再一次,我想知道您认为这有多安全,以及如何改进它以使其在实际使用中可以接受。 (如果可能的话。) &我也想尽我所能避免“可逆”哈希。 (即创建我自己的方法来确保密码匹配的想法,我想让它更像是一个最佳猜测假设,以完全帮助确保攻击者不可能反转数据库中的密码。

& 是的,我知道这很愚蠢,因为它很可能会导致更多安全漏洞,而不是帮助修复它们。但这只是我在玩弄的东西,也许希望使它实用。


其他信息:

1) 密码使用唯一的盐存储(因此不是 1 个帐户共享相同的盐)

2)密码盐总是在变化(每次用户帐户成功登录时,它都会更改数据库中的用户盐。我这样做是为了更改数据库中的哈希,从而减少密码冲突频繁(希望)以及防止不需要的用户多次使用相同的错误密码登录(如果他们设法遇到一个,实现这一点的唯一方法是通过暴力破解或“猜测”,任何登录系统都容易受到攻击)。

当我说密码冲突时,我的意思是“你好”和“蓝色”这两个词共享相同的确切字符数(正如我解释的,我计算单个字符 + 数字,并比较它们,以假设它正确的密码。)

3) 我也可能会保留散列密码的前 3 个字符/数字不受 str_shuffle 的影响,以帮助确保密码正确。 (通过创建 2 个检查,1)检查两个字符串是否共享相同的 FIRST 3 CHARS/Numbers & 2)然后比较每个字符串中的字符数。 (希望再次减少密码冲突)。

4) 显然会添加其他安全措施(即最大登录尝试次数、验证码等。以帮助防止自动暴力破解,使黑客更难找到可能的密码或真实密码。

我已经成功地完成了这个 PoC,它就像一个魅力,虽然我还没有针对字典攻击/蛮力攻击测试 PoC,以查看密码冲突的可能性。以及它们的频率。

如果我说了很多“无用”的信息,请忽略它。我只是尽力合理地解释这一点。

【问题讨论】:

标签: php security hash password-protection whirlpool


【解决方案1】:

这对我来说似乎非常无效和不安全。

最值得注意的是:碰撞。您在其他信息中已经提到过。

只需检查散列和加扰中的字符数,就可以让冲突概率飙升。您可以启用一个密码,使其对其哈希的所有排列也有效。考虑到漩涡哈希中 128 个字符的长度,这是一个非常大的数字。

因此,基本上,通过允许这一点,您允许潜在的暴力破解者通过输入一个密码来一次检查数千个密码。

他们不会获得对系统的永久访问权限,因为您说过每次登录后都会更改哈希,但是他们获得一次访问权限的可能性大大增加。

关于改变盐...你是怎么做的?除非您在散列之后而不是之前应用盐,否则我想不出办法,这不是盐在散列中的工作方式。

如果你想让它更安全,那么只需使用多次哈希迭代。存储散列密码和散列迭代次数。每次用户登录时再次哈希哈希,存储它,并增加迭代次数。这将充分改变存储的哈希值,而不会引入太多的加密弱点。

【讨论】:

  • 对于盐的事情,当用户正确登录时,它使用纯文本密码(在检查它的“正确”密码与数据库中的密码相比之后)然后生成一个新的盐为它,并重新散列它,再次洗牌。然后将其存储回数据库中。 & 感谢 cmets,我会进一步了解您现在所说的内容 :)。
  • 哦.. 好吧,想想以下。我是一个暴力破解者,刚刚成功地随机创建了一个碰撞。现在我的随机密码刚刚覆盖了您的原始密码,因为基于我的随机密码的哈希存储在数据库中。这给了暴力破解者完全的永久访问权限,并关闭了初始用户/密码。
【解决方案2】:

您的洗牌方案会使密码的安全性降低。在随机播放后比较字母和数字实例的数量会增加两个人具有相同密码值的机会(如您所说的冲突)。

重新加盐是您可以使用的。用户每次登录成功后,可以重新加盐密码,再次保存。如果您修改 PHP 密码程序以使用高分辨率时间值,这可能会更好,从而增加唯一性。本质上,您正在不断地旋转密码的盐。您必须保存清除密码,将其哈希值与保存的密码进行比较,重新加盐并哈希清除密码并再次保存。

【讨论】:

    【解决方案3】:

    加密强哈希函数的输出对于所有意图和目的来说都是伪随机的。试图通过扰乱它来增加熵什么都不做。它不会使散列不那么“可逆”,因为“反转”散列的唯一方法是选择输入,对其进行散列,将其与散列进行比较;这与登录用户时必须做的事情相同,攻击者必须做的事情相同,更改比较算法不会更改此基本操作。 (正如其他人所指出的,您的弱化比较算法实际上有助于攻击者。)

    处理这个问题的公认方法已经足够了:

    1. 通过使用(伪)随机噪声对其进行加盐,确保您的输入是唯一的,这会迫使攻击者进行实际的蛮力散列。
    2. 选择一个较慢的哈希(最好是 bcrypt 或 scrypt,具有足够高的成本因素,使您可以执行一次,但攻击者无法执行数十亿次),这使得它在计算上不可行攻击者在其生命周期内暴力破解哈希。

    如果两个步骤都正确完成,“反转”哈希已经不可行。无需额外的智力游戏。

    【讨论】:

      【解决方案4】:

      不要再摆弄你的想法了。这是不安全的。

      只有大约两种密码安全方法可以提供足够的防篡改能力:

      1. 使用执行 HMAC-SHA1 之类的硬件安全模块。模块是外部硬件,外界不知道模块内部的内部秘密(只能通过物理访问模块获得),没有该模块,生成的哈希将永远不会被重建。作为具有“快速”散列算法的专用硬件,这使其成为大量密码检查的可行解决方案。详情请见http://en.wikipedia.org/wiki/Hash-based_message_authentication_code
      2. 使用非常慢的散列算法。诸如“scrypt”或“bcrypt”之类的东西将执行得非常慢,从而阻碍了密码列表对已知哈希列表的快速暴力扫描。 PHP 目前只支持“bcrypt”。

      您可能想知道为什么应该使用封装秘密的外部硬件。很简单:任何可以从进行散列的机器访问的东西都可能被窃取。窃取机密就像对所有密钥使用相同的盐(或根本不使用):您最终“仅”拥有一个非常快速的散列算法,并且所有其他组件都已知,并且可以立即开始暴力破解密码。

      因此,如果没有专用硬件,唯一的其他选择就是慢速密码哈希算法。

      有一个针对 PHP 的解决方案:password_compat 是一个库,它为 PHP 5.5 之前的版本重新实现了 PHP 密码哈希 API。如果您已经在使用 5.5,则只需使用 these functions

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-09-03
        • 2014-12-10
        • 2011-05-28
        • 1970-01-01
        • 1970-01-01
        • 2013-02-09
        • 2021-08-14
        • 2013-03-16
        相关资源
        最近更新 更多