源代码可用时如何正确保护密码?

How do I properly protect a password when the source code is available?

我正在构建一个 Web 应用程序,该应用程序具有我希望尽可能安全的用户登录功能。创建新用户时,我使用此 javascript 函数对用户信息进行哈希处理,并最终将输出存储在 mySQL 数据库中:

function hash(user) {

    var part1 = mix(user.username, user.password);
    var part2 = mix(user.random_value + salt, user.password);

    return mix(part1, part2);

    function mix(part1, part2) {

        var hash = sha3_256(part1 + part2);

        var rehash = 10000;
        while(rehash--) {
            hash = sha3_256(hash + salt + rehash);
        }
        return hash;
    }

}

数据库包含用户名、随机值和散列函数的输出,而 salt 变量是一个随机字符串,在函数外部声明并且永远不会改变。

据我通过阅读以前的一些关于密码安全的帖子了解到,这是一种相当安全的做事方式(尽管我会很感激任何建议),但这是我的担忧:

如果我假设某人可以获得对数据库的访问权限并获取为某个用户存储的所有信息,并且假定他可以准确地看到哈希函数的运行方式(因为此代码在浏览器和 GitHub).难道这个恶意的人不能通过我的函数 运行 8 个字符(最小密码长度)的所有可能组合,看看密码的什么值创建正确的哈希值?

这肯定需要一些时间,但并非不可能 运行 最终通过所有可能性并因此获得帐户访问权限。

有什么方法可以防止这种攻击吗?

谢谢!

旁注:我假设您正在执行此服务器端(nodejs?)。您的实现是非标准的,并且您的术语混淆了(正常术语具有 "salt" 作为每次更改的值,而 "pepper" 是固定的服务器端字符串),但它确实具有主要到位的概念。我建议您使用标准 "password hashing" 算法,例如 scrypt 或 bcrypt。

关于你的问题“这个恶意的人难道不能通过我的函数 运行 8 个字符(最小密码长度)的所有可能组合,看看密码的值是多少创建了正确的散列 ?",答案是肯定的,但他要花很长时间才能做到这一点。这就是 rehash 变量的全部目的:减慢用户的速度。请参阅:Our password hashing has no clothes 了解更多详情。

您的威胁模型是 "attacker gets complete read access to database contents",是吗?

解决方案是:

  1. 不要让这种事情发生
  2. 将 Web 服务器与数据库服务器隔离,并使用 Peppering

这涉及在网络服务器上存储秘密(从不在数据库服务器上)。首先使用它来 HMAC 密码。然后对其进行哈希存储。

如果数据库服务器遭到破坏,密码将无法轻易破解。如果攻击者可以进行 SQL 注入,但无法获取 Web 服务器信息

,这甚至会起作用

备注:

  1. 不要使用 SHA{anything} 进行密码哈希处理。仅使用 bcrypt、scrypt 或 PBKDF2
  2. 不要推出自己的安全系统。使用现有框架
  3. 即使是开源系统,您的系统也应该是安全的。参见 https://en.wikipedia.org/wiki/Kerckhoffs%27s_principle
  4. 运行 网络上的 HIDS 和网络上的数据库服务器和 NIDS,这样您就可以(希望)检测到漏洞并通知您的用户,以便他们可以更改其他站点上的密码

如果您使用的哈希算法足够好,那没关系。那是因为(强调我的)

A cryptographic hash function is a mathematical algorithm that maps data of arbitrary size to a bit string of a fixed size (a hash function) which is designed to also be one-way function, that is, a function which is infeasible to invert.

密码哈希被设计成开源的,在明文密码存储上使用它们的目的是,如果数据被破坏,root 密码是不可逆的。 Wiki on this

现在,如果您已经推出了自己的产品,或者试图阻止别人知道您使用的是弱散列算法,那么您就有麻烦了。

此外,您的盐/胡椒应该只存在于应用程序的实例化中。您当然可以将其加载到 github,但我建议您在实时应用程序中更改该配置。

通过每8个字符的密码来解决您对运行的担忧,那只是一个rainbow table concern. Which is why using hunter2 is a bad password. Your salt/peppering helps mitigate that but in general, guessing is infeasible. This是一个很好的时间解释。