如何在数据库上安全地存储用户名/密码(哈希不会这样做)

时间:2013-04-23 09:26:24

标签: security postgresql grails passwords grails-plugin

想象一下这种情况:您的用户会为您提供访问第三方服务的凭据(用户名/密码)。因此,您必须在连接到服务时生成这些凭据,您不能只存储盐渍哈希。

环境是Grails,psql为DB。从程序员的角度来看,理想情况下,用户/密码仍然是域对象的一部分(因此它们易于使用)。

安全存储它们的最佳做法是什么?

1 个答案:

答案 0 :(得分:2)

*(我不是安全或加密专家;这是我的理解,基于我的阅读和研究,但与权威建议相去甚远。获取网络应用安全专家的建议并获得适当的安全审核。)*

您真正做的最好的事情就是当用户未主动登录时,您的应用无法解密它们。

使用部分基于用户的原始未散列密码的密钥加密凭据。您从不存储用户密码以登录您系统上的服务,当然,因此您只能在身份验证期间短暂访问它(并且只有因为网络没有赶上在90年代中期,采用了理智的挑战 - 响应认证方案)。您可以在用户登录时解密第三方服务的已保存凭据,并将其存储在用户的易失性服务器端会话中。

对于加密密钥,您可以使用您为每个(用户,第三方凭证)对随机生成的大量盐值对用户名和用户原始密码进行散列,并将其与加密凭据一起存储。盐应该与用于存储哈希密码的盐不同。

这远非理想,并且存在各种问题 - 但是在用户会话到期后,或者他们记录我们并清除会话时,凭据将无法访问。

这也意味着当您的应用未主动登录时,您的应用无法代表他们行事,这种限制可能会根据您的要求为您提供支持。

较弱的选项是为重新启动应用程序时系统管理员手动输入的所有用户凭据创建密钥。此密钥必须存储在内存中,但它至少不会位于磁盘或数据库中,因此窃取数据库转储的人将更难解密存储的凭据。

如果攻击者找到一种方法来欺骗您的应用在解密后泄露这些域对象 - 或让它们冒充该用户,让其代表另一方执行对第三方服务的操作,则这两个选项都不会对您有所帮助但是,它至少可以防止数据库转储和类似攻击被盗。

进一步的建议:不要将pgcrypto用于数据库中的加密,而是在应用程序端执行。这意味着DB永远不会看到解密数据所需的密钥材料;它永远不会泄漏到数据库日志中,嗅出pg_stat_activity等等。