我们有一个基于浏览器的客户端服务器应用程序。客户端使用电子邮件和密码注册。密码被强制执行到一些指南中。
用户需要服务器上的加密金库来存储加密密钥,这样只有客户端设备上的用户才能解密和恢复密钥以供临时使用。
因此,服务器或其他任何人都不应该访问这些加密密钥。只有客户端的用户才能恢复它。
步骤2-4中使用的3种盐类可以通过使用SHA3-512从电子邮件中派生出来,并获得这些函数所需的字节长度?
我在想,服务器不知道如何解密金库是很重要的。因此,在任何时候都不应该知道金库的秘密钥匙。只使用一个密码登录和加密听起来不合理吗?有人会怎么处理这个问题呢?
发布于 2019-03-14 16:13:26
我认为我提议的重复应该告诉你“是的,你正在以一种合理的方式去做这件事”,但是有几点我认为值得单独讨论。
步骤2-4中使用的3种盐类可以通过使用SHA3-512从电子邮件中派生出来,并获得这些函数所需的字节长度?
盐类不应再利用,也不应是可预测的。通过使用用户名的散列,每当用户更改密码时,都会使用相同的salt。它还允许攻击者对将要使用的盐进行琐碎的预测,并开始生成彩虹表,希望将来的泄漏将允许他们利用它。
在登录密钥盐的情况下,由于它必须在登录前使用客户端,任何知道用户名的人都必须能够从服务器中检索到盐,因此从用户名生成salt在这里可能不是一个交易破坏者,但是在用户更改密码时仍然最好避免使用相同的salt。加密密钥盐应该随机生成,以防止彩虹表的预计算,这意味着它需要存储在服务器上(除非用户不能更改浏览器/计算机)。
如果您将其与一个只向服务器发送密码的普通应用程序进行比较,那么对于外部攻击者来说,这并不是不安全的。要让使用登录密钥盐的彩虹表有用,就必须有人获得用户的登录密钥,而在其他应用程序中,这将是密码本身。
如果加密密钥salt只发送给经过身份验证的用户,那么唯一可以生成的彩虹表将用于用户的登录密钥。如果存在数据库泄漏,则登录密钥的服务器端bcrypt散列将具有彩虹表不会有用的单独随机盐,加密数据将使用攻击者无法事先访问的加密密钥盐加密,因此允许任何人访问登录密钥盐不会造成太大威胁。
当然,如果服务器本身是恶意的,没有什么可以阻止它试图破解密码,但这不是真的可以避免的。
我在想,服务器不知道如何解密金库是很重要的。
虽然这听起来确实不错,但除非您的用户采取极端措施(即审核代码,并在每次加载页面时确认代码没有更改),否则他们仍必须在一定程度上信任服务器。每当他们加载页面时,服务器都会向他们发送JavaScript,而控制服务器的恶意人员很容易修改代码,让他们向他们发送加密密钥。
客户端加密的密钥仅为用户所知,如果服务器在未来受到破坏,则可以减少所造成的损害,但如果用户在服务器受到威胁/恶意时连接到服务器,则可能会倒霉。
因此,在任何时候都不应该知道金库的秘密钥匙。只使用一个密码登录和加密听起来不合理吗?
通过bcrypt和HKDF客户端运行密码,为加密密钥和身份验证提供单独的盐类,就足以解决这个问题。请注意,从历史上看,JavaScript并不是一个很好的密码哈希选择,因为它的速度。如果本机实现比JavaScript实现快10倍,则为了相同的安全性,JavaScript必须运行10倍的时间。WebAssembly实现可能工作得更好,但建议进行基准测试。
发布于 2019-03-15 06:55:37
这正是我们在设计1 1Password (我为之工作)时所面临的问题。如果您想要血淋淋的细节,请看一下1个密码安全设计文档。(请注意,如果今天设计那个KDF,我们会做一些不同的事情。用它来激发灵感,但不要完全模仿它。)
虽然许多细节是不同的,但我们采取的总体方法是相似的。我们使用不同的salt和不同的HDKF信息来派生“主解锁密钥”,而不是用于派生长期客户端身份验证秘密。
请注意,我们,像您一样,从来不想接收用户的秘密。所以你所称的LS从未被传送过。相反,我们使用密码认证的密钥交换机制,特别是SRP。不管它的价值如何,我们已经开源了我们的SRP实施。我们确实从服务器上提供了salt,但在将来的版本中,我们可能会屏蔽salt,这将防止一些预计算攻击。
你的选择是个不错的选择。您可能希望考虑内存硬KDF,如Argon2或氪。在我们的例子中,我们被PBKDF2困住了,因为我们需要在web浏览器中进行优化的实现。但是,如果你不想拥有一个网络客户端,那么一定要至少考虑使用bcrypt或内存硬KDF之一。
关于PBKDF2的另一个注意事项是不要将它用于键拉伸。你正确地使用HKDF键拉伸,但我想为其他阅读这一警告。在PBKDF2中有一个设计错误,在某些情况下,当它被用于键拉伸时,会在后面咬你。
慢散列的
尽管bcrypt等是必要的,但在某个点上,所有这些慢散列会产生递减的回报。。人们会使用bas密码。因此,我们在密钥派生函数中添加了一个仅存储在客户端上的高熵秘密。这将与主密码客户端相结合。如果没有客户端保存的秘密,我们保存的数据就不能用于密码破解。
我建议使用随机盐类,而不是从用户名中派生它们。这确实意味着当用户设置新客户端时,您的服务将需要将salt传输给用户,但您确实应该在客户端和服务器之间使用一些挑战/响应,以避免传输您的登录秘密。
如果您仍然希望从用户名中派生salt,那么SHA3-512对于盐的创建是过分的。你根本不需要盐就这么长。salt的目的是避免密钥与相同密码的冲突。对于一个盐来说,16个字节就足够了。
https://security.stackexchange.com/questions/205353
复制相似问题