安全保存清晰密码的最佳方法是什么?

信息安全 密码 日志记录 河豚
2021-08-16 21:39:47

我正在开发一个将连接到数据库的 Web 项目。为此,我必须清楚地存储该数据库用户的登录名/密码(以对称方式加密),以便能够重新连接每个操作(如创建表、添加条目等)而无需请求每次都有这些凭据。

我知道以明文形式存储密码太不安全了,而且我不可能。

这就是我的想法,你能告诉我它是否正确或/以及是否有更好的可能性?谢谢 :)

应用程序将分为两个独立的部分:前端和后端。

当用户通过前端登录时,会以明文形式发送登录名和密码(我会推荐使用 HTTPS)。后端会尝试连接数据库,如果连接成功,它会使用Blowfish对登录名和密码进行加密,并将它们返回给前端。

对于任何后续请求,前端将不得不发送加密的登录名/密码,而不知道明文的,只知道加密的。

如果有人可以访问该用户的数据(例如 XSS),他将只能访问加密的凭据,而不能访问明文的凭据。

如果攻击者可以进行 MITM,那么只有初始登录是有风险的,所有接下来的请求都将使用加密的凭据。

我考虑过使用 cookie/会话,但它是相同的:值以明文或 base64 编码存储。不是很安全!

Blowfish 的想法来自 PhpMyAdmin 如何使用它(又名,相同)。此外,即使在 PhpMyAdmin 上,登录部分也是明文发送的。

你认为我的实现是正确的,还是你有更好的建议?我真的很想做一些尽可能安全的事情。到目前为止,只有登录部分困扰着我:/

谢谢你的想法。

编辑:

显然,我的问题不够清楚,我会尝试更明确

我想构建 PhpMyAdmin 的替代方案。PhpMyAdmin 是一个中间件,它通过提供该数据库中任何用户的登录名/密码来连接到 MySQL 服务器。Web 表单中询问的凭据是用于 MySQL 数据库的凭据。

因此,在用户成功登录后的整个会话期间,PhpMyAdmin 通过使用 Blowfish 加密密码将登录名/密码存储在会话中。

这是无法避免的,因为每次用户发出请求(如创建表、插入数据、更新或删除数据)时,PhpMyAdmin 都需要使用登录时提供的凭据重新连接到该数据库,然后执行用户操作请求。

然后,PhpMyAdmin不可能只存储凭据的哈希值,因为在同一用户发出的后续请求期间,它将无法重新连接到数据库。

我知道存储可以明文检索的密码根本不是一个好的解决方案,这就是这个问题的原因:不要告诉我散列更好,因为在我的情况下它绝对没用,但要知道是否有是比对称加密 + HTTPS 更好的选择,用于保存用户执行的每个操作所需的密码。

4个回答

现在问题已经被修改,我明白你想要做得更好。

简短的回答是:只需将数据库密码明文存储在(服务器端)会话对象中。你不能做得更好。

如果您愿意,您可以加密数据库密码并将加密后的密码存储在会话对象中,但实际上没有意义,因为您要将密钥存储在哪里?没有任何地方可以存储比会话对象更安全的密钥。您可以将密钥存储在配置文件或全局变量中,但实际上,我不确定这是否会增加针对任何现实威胁的任何安全性。很难理解为什么要打扰——这对我来说就像安全剧院。

因此,只需让用户在会话开始时输入数据库密码,将数据库密码存储在会话状态中,然后就可以完成了。没有比这更好的了。

看在上帝的份上,请使用良好的 Web 应用程序编程实践。查看 OWASP 资源。确保您熟悉网络世界中常见的网络漏洞。使用良好的安全实践仔细编写代码。并请其他了解安全知识的人对您的代码进行安全审查。如果您的代码中存在安全漏洞,就会发生不好的事情。

您不需要以可恢复的格式保存凭据,即使它们已加密。如果您的后端应用程序可以解密某些东西,那么任何可以破解您的后端应用程序的人都可以。确实,您必须假设您的后端应用程序迟早会受到损害,并在设计时考虑到这一点。

最安全的方法可能是使用bcryptPBKDF2之类的算法将密码存储为加盐和散列。如今,使用 MD5 或 SHA1 之类的常规散列/加盐还不够安全。hashcat这样的程序可以非常快速地破解密码文件。 这篇关于 hashcat 的文章非常值得一读

您担心有人可以访问 cookie 商店,这很好。cookie 基本上是密码等价物,因此如果您要存储这些,它们也应该是加盐哈希。

真的,这看起来很容易,但有很多极端情况。 如果您的应用程序框架已经有一种方法来进行会话管理,那么您可能应该只使用它而不是自己滚动。

查看OWASP 会话管理备忘单,了解一些好的建议。

第一:你确定?首先,检查以确保您是否真的需要以明文或可恢复的形式存储密码。您的问题没有解释为什么这是必要的。如果您有安全漏洞,每个人都会质疑您的决定,如果您以可恢复的格式存储密码,您的组织可能会遭受一些声誉损失。因此,请确保这确实是必要的。

下一步:定义问题。 那么,你到底想做什么?这个问题不是很清楚,所以我会做一些猜测。如果这些猜测不准确,请在考虑更多之后编辑问题。

假设:用户登录到您的 Web 应用程序,我们称之为 CyrilApp,使用您的应用程序的用户名和密码。您希望您的代码能够访问他们的其他帐户——例如,通过 IMAP 访问他们的电子邮件——因此您要求他们输入他们的电子邮件用户名和电子邮件密码,以便您的服务器代码稍后使用。现在您想知道如何尽可能安全地存储电子邮件密码。是关于这个想法吗?

如果这是问题所在,那么您需要考虑几个问题:如何存储电子邮件密码?找回邮箱密码时,如何安全使用?如何限制对电子邮件密码的访问?

贮存。 一种选择是将密码存储在硬件安全模块 (HSM) 中,或在 HSM 管理的密钥下加密。但是,HSM 非常昂贵,因此这可能不可行。

更实用的解决方案是构建一个单独的服务,我们称之为 EmailPasswordStore,它执行一个狭窄而简单的功能,经过仔细编码,并且可以安全地存储电子邮件密码。它可能会提供一个 API 允许 CyrilApp 代码存储用户的电子邮件密码(当他们输入密码时),以及一个允许 CyrilApp 代码请求使用密码的 API(例如,EmailPasswordStore 可能会打开一个 IMAP 连接到IMAP 服务器,发送用户的电子邮件用户名和电子邮件密码,然后在 CyrilApp 和 IMAP 服务器之间来回中继字节。

在这个架构中,电子邮件密码永远不会离开 EmailPasswordStore,而 EmailPasswordStore 的工作是确保这种情况仍然存在——即使 CyrilApp 被破坏或您的其余服务器被攻击者控制,EmailPasswordStore 需要防止攻击者获取电子邮件密码。您可以在单独的机器(或可能在单独的 VM)上运行 EmailPasswordStore,在 CyrilApp 和 EmailPasswordStore 之间使用 VPN,并对 EmailPasswordStore 代码进行仔细的安全审查。

利用。安全地存储电子邮件密码是不够的,因为在某些时候您会想要使用它们。如果您只是以某种加密形式存储电子邮件密码,然后在您想使用它们时对其进行解密,那么您并没有获得太多的安全优势:破坏您的 Web 应用程序的攻击者可以悄悄地坐下来窃取每个使用的密码,或者甚至可能解密所有密码本身。因此,您需要一些使用控件。

上面列出的建议的 EmailPasswordStore 架构提供了这些控件。它使用电子邮件密码本身,并且从不向您的 CyrilApp Web 应用程序透露密码。试着看看你是否可以在你的环境中做类似的事情。

限制访问。最后,您可能希望限制谁可以请求 EmailPasswordStore 使用密码。一个好的起点是 EmailPasswordStore 对连接到它的服务进行身份验证;例如,您可以在 CyrilApp 和 EmailPasswordStore 之间设置 VPN,并确保 EmailPasswordStore 将拒绝所有其他连接尝试。

更复杂的架构可能会验证当前登录用户的身份,并限制仅访问该电子邮件密码。例如,EmailPasswordStore 可以存储用户用于登录 CyrilApp 的哈希密码列表,并要求 CyrilApp 在解锁用户的电子邮件密码之前将用户的登录密码发送到 EmailPasswordStore 进行验证。但是,在某些设置中这可能是不必要的。

进一步阅读。另请参阅在哪里可以安全地存储源可见的系统的密钥?以及 在哪里存储用于加密的密钥

  • 当用户通过前端登录时,会以明文形式发送登录名和密码(我会推荐使用 HTTPS)。后端会尝试连接数据库,如果连接成功,会使用 Blowfish 对登录名和密码进行加密,并返回给前端。

您应该改用盐渍哈希。

  • 对于任何后续请求,前端将不得不发送加密的登录名/密码,而不知道明文的,只知道加密的。如果有人可以访问该用户的数据(例如 XSS),他将只能访问加密的凭据,而不能访问明文的凭据。

通过 javascript 中的河豚实现?如果攻击者知道加密密码,他可以关闭 javascript 并在不知道原始密码的情况下发送该密码。

  • 如果攻击者可以进行 MITM,那么只有初始登录是有风险的,所有接下来的请求都将使用加密的凭据。

如果有人尝试 MITM HTTPS,您将收到无效证书警告(除非他们设法获取您的私钥或以某种方式伪造它,这不太可能)在这种情况下,您只需停止尝试加载页面并且不会造成任何损坏。