在数据库中存储敏感数据的建议

5

我正在寻找在数据库中存储敏感数据的最佳解决方案。

我知道这是一个常见的问题,而且我已经做了我的功课(至少我是这样认为的),但在做出决定之前,我想在这里问问。

假设:

  • 加密的数据需要被解密。我们谈论的是SMTP凭据,如用户名、密码、主机、端口等。

我考虑了两个概念:

  1. Encrypt data with help of passlib.totp library. To make those data a bit safer i will keep key in separate file. Then from what i can see i can use this library to decrypt data to plain text using my key.

  2. The other concept was to encrypt and decrypt data during query request with help of postgres:

    insert into demo(pw) values ( encrypt( 'data', 'key', 'aes') );
    

    And:

    decrypt(pw, 'key', 'aes'), 'utf-8')
    

    Here the key will be stored also in separate file.

所以我的问题是:

  1. 在代码中还是在数据库中加密/解密数据的方法更好?
  2. 有没有比passlib.totp更好(更强大)的库可用 -> 我对该库没有经验(我知道加密/解密不是存储密码最安全的方式 -> 密码应该被哈希,但我需要明文密码来使用用户smtp网关)。

3
问问自己一个问题:这会保护你免受什么样的威胁?因为显然,如果有人能够访问您的系统,密钥以及数据库内容都可能会被泄露... - Błotosmętek
是的,我知道这一点。然而,如果有人仅通过 SQL 注入(由于输入字段保护不足)获得访问数据库内容,那么我认为这将为这些数据提供一定程度的保护。我完全意识到这不是100%坚固的概念。再举个例子,你有员工想要访问读取数据库(或其中的一部分),但你不想让他们看到明文密码,他们也无法访问文件结构。因此,我认为在某些情况下这是有用的方案。 - szikael
1
始终在客户端进行加密和解密。否则,人们可能会读取你的明文网络流量。这并不完全涉及编程,因此请转至https://security.stackexchange.com。 - OneCricketeer
1
好的,除其他因素外,这有助于在系统外时备份不会不安全。此外,一些国家对数据泄漏/丢失情况下的义务立法,并区分加密和未加密。也许这是一个更适合 https://security.stackexchange.com/ 的问题。 - JL Peyret
这似乎是你设计中最大的问题:“...密钥也将存储在单独的文件中...”加密数据的密钥可能需要放在受保护的存储中,而不是散落在文件系统中。您还应该考虑提示用户提供一些额外的熵(即密码)以添加到受保护存储中的秘密中。您还应该熟悉操作系统提供的KeyChain的工作原理以及如何有效地使用它。另请参见Gutmann的《Engineering Security》(https://www.cs.auckland.ac.nz/~pgut001/pubs/book.pdf)。 - jww
显示剩余2条评论
3个回答

2

2) 另一个概念是使用Postgres在查询请求期间加密和解密数据:insert into demo(pw) values ( encrypt( 'data', 'key', 'aes') ); and decrypt(pw, 'key', 'aes'), 'utf-8'),这里的密钥也将存储在单独的文件中。

我不建议这样做,因为在pg_stat_activity、日志等方面很容易暴露密钥。PostgreSQL没有日志掩码功能来保护它。

我强烈建议您使用应用端加密。如果安全性至关重要,请使用加密卸载设备,以便大多数攻击者无法提取密钥。或者要求管理员在应用程序启动时输入密码短语以解锁密钥,以便密钥永远不会以未加密的形式存储在磁盘上 - 然后攻击者必须从内存中窃取它。但是,即使在某个非常规的地方存储未加密的密钥文件,也比使用数据库加密更好,因为它至少将密钥与数据分离。


谢谢。至少我现在知道选项2是完全错误的。 - szikael

0

最终,您的应用程序需要能够使用某种密钥恢复明文密码。如果您的系统受到攻击,您必须假设恶意用户将简单地找到您的密钥(无论是在数据库中还是在磁盘上),并执行与您的应用程序执行的完全相同的解密。

当您的系统需要以可恢复的形式存储密码,即用于与外部系统进行身份验证时,您最多只能混淆该信息。这就是人们所说的“安全性通过混淆”,这是一个不好的想法。

当你给出安全的外观,却没有实际保护某些东西时,这可能会使事情变得更加危险。您或其他管理系统的人可能会忽略其他重要的安全措施,因为他们认为敏感信息已经有一层保护。它可能会创造一种社交情况,敏感信息可能比假定只有保护保存它的系统才能保护信息的情况下更容易泄漏。它还可能导致人们相信,如果从数据库中窃取数据,“也许没关系,因为他们无法解密”。这就是您最终要对向广大世界泄露凭据负责的方式,因为您必须假设如果您的应用程序可以获取明文数据,那么已经入侵您的应用程序的攻击者也可以获取。

在多个系统上加密多部分密钥(即一部分在文件系统中,一部分在数据库中)可能会有一个非常微小的优势,这样获得其中一个系统访问权限的人不一定能够获得另一个系统的访问权限。可以说,这可能会延迟攻击或阻止懒惰的攻击者。然而,通常情况下,您的应用程序所在的位置已经可以访问这两个东西,因此如果您的应用程序被攻击,则必须假定数据已经被泄露。(编辑:您在另一条评论中提到您有用户a)不应该知道存储在数据库中的密码,但b)将直接访问数据库。相信我,如果您这样做,这些用户中有一个获得所有这些密码的非零机会。通过走这条路,您正在把信任放在一个有缺陷的保护层上。)

简而言之,在存储敏感数据时进行可逆加密很少具有实际的安全价值。如果您试图勾选合规性复选框,并且您没有权力否决需要您勾选该框的上级,则请实施“加密”数据的某些内容。但是,如果您真正想要保护您的系统,请寻找其他方法:这里有危险。


1
无论如何,感谢您花时间写下所有这些内容。很难不同意您的观点。但它并没有回答我的主要问题。问题是:如果我必须加密解密(原因不重要),在代码中或通过数据库哪里更好,如果在代码中,最合适的工具是什么。那就是这个问题的主要目标。我没有问“我是否应该这样做”->这根本不在这个问题的范围内。但无论如何,感谢您的有趣演讲。 - szikael
@daveruinseverything 最好的保护密码的方法就是不要存储它们 :-) 尽管以上答案是基于攻击者完全控制系统的假设而作出的。虽然我不是专家,但在大多数情况下,从能够在服务器上执行查询到获得完全访问权限更加困难。在这种情况下,不以混淆形式存储这些访问凭证是否有帮助呢? - Greg0ry

0
您可以查看 Vault项目,这是一个管理机密信息的工具:
常规机密存储 至少,Vault可以用于存储任何机密信息。例如,使用Vault存储敏感环境变量、数据库凭据、API密钥等都是非常棒的方式。
相比之下,目前的存储方式可能是文本文件、配置管理、数据库等中明文存储。使用vault read或API查询这些机密信息将更加安全。这样做既保护了这些秘密的明文版本,也记录了Vault审计日志中的访问记录。
员工凭证存储 虽然与“常规机密存储”有所重叠,但Vault是存储员工共享以访问Web服务的凭证的好机制。审计日志机制可以让您知道员工访问了哪些机密信息以及何时访问。员工离职时,更容易滚动密钥并了解哪些密钥已经被滚动过,哪些没有。

Vault服务器以加密形式存储数据。可以通过命令行或REST API检索数据。服务器必须处于未封存状态才能返回解密的数据 - 解封需要主密钥的特定数量碎片。一旦服务器重新启动,您需要再次解封它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接