通过将密码哈希推送到客户端,您会将它们暴露于离线暴力攻击。如果密码足够强,那是完全可以接受的。但这是一个危险的假设。
您可以要求每个用户确认他们希望发布自己的哈希(在向他们解释风险之后)。但是有很多用户会高兴地说他们了解风险并选择了足够强的密码,即使他们实际选择的是password12345!!!
此时,您必须评估此功能与允许用户在脚上开枪的风险相比的重要性。
然而,您的设计中还有另一个缺点,那就是验证离线更新。依靠客户端来验证用户是不够的。
将用户密码与更新一起存储并在联机后将两者发送到服务器将解决仅执行客户端验证的问题。但是你会引入三个新问题:
- 输入更新时,它不会捕获输入错误的凭据。稍后,当服务器验证这些凭据时,最初键入它们的用户可能无法解决该问题。
- 更新将具有延展性。修改存储在客户端设备上的更新以使其在到达服务器后执行不同的更新将是微不足道的。
- 您将在设备上以明文形式存储密码,这是安全方面的一大禁忌。
我没有看到任何方法可以防止密码的离线暴力破解,同时仍然允许在输入更新时验证密码,并且出于可用性原因,验证是必要的。
因此,我将采取的方法是根据用户密码和盐创建一个公钥对,并使用相应的私钥对更新进行签名。这意味着更新不再具有延展性,并且不需要存储和传输密码,而您只需存储和传输签名。
当然,客户端仍然需要知道盐和用户名才能生成正确签名的交易。它首先需要知道公钥或哈希来验证它,这允许离线暴力攻击。
您可以将经过哈希验证的客户端截断为仅一个字节,这使得离线暴力攻击不太可行,并且仍然有 99% 的机会在客户端检测到不正确的密码。
在服务器端,您仍应使用加盐散列验证传输的公钥,以确保您只收到有效交易。
显然,您正在设计的应用程序的任何设计都会留下很多错误空间,因此必须由多名安全专业人员审查最终设计和代码,以确保最终结果是安全的。