加密 MySQL 数据库中的 IP 地址

信息安全 加密 哈希 php 数据库 mysql
2021-08-16 17:10:36

我想加密我的 MySQL 数据库中的 IP 地址,具有以下约束:

  • 不需要抵抗可以执行查询的攻击者。
  • 必须能够抵抗有权访问磁盘上文件的攻击者。
  • 必须能够根据加密形式验证 IP,以检查它是否匹配。
  • 检查/24通配符(例如10.20.30.*)也会很有用。
  • 系统启动时无法输入任何形式的密钥或密码,因为这将在数据中心的服务器上运行,并且每次重新启动都通过 SSH 登录是我可以做到的痛苦。

我目前正在使用单独的数据库连接来提供更好的权限限制,并使用单独的密码表。我还使用 MySQLi 和半自动代码审查来确保没有 SQL 注入漏洞。

使用非加盐(即确定性)哈希机制,很容易计算所有可能的 IP 哈希。使用加盐散列可以减少这个问题,但如果攻击者只是试图破坏一个 IP 散列,它仍然不会好多少。当然,所有这些都可以防止通配符搜索。

有针对这个的解决方法吗?


更新:
经过一番思考,我想出了以下方案:

  • Webapp 在源代码中嵌入了一个 4096 位 RSA 公钥,我将私钥保存在我家用机器上的 TrueCrypt 卷中。
  • 在向日志表中插入条目时,IP 会用随机字符串填充并使用公钥加密。这使得解密变得不可能,并使加密变得不确定。
  • webapp 提供了一个用于导出日志的 API,只能由经过身份验证的管理员用户通过 SSL 访问。
  • 我编写了一个应用程序来使用 API 来浏览我的家用机器的日志,使用私钥来解密 IP 地址。
  • 当 IP 地址被禁止时,IP 以明文形式存储在禁止表中。

有什么意见或建议吗?

4个回答

公钥/私钥加密很慢。它非常适合编写并忘记它,但这不是一个快速的过程。

为了速度,考虑一下:使​​用随机生成的对称密钥,该密钥在守护程序启动时选择,并且可能每小时、每天、每周或每月轮换一次(取决于您的流量和安全需求)。仅将该密钥保留在内存中,并使用您的密钥对的公钥将该对称密钥加密到数据库表中。然后您可以恢复密钥,但攻击者无法获取它,除非通过转储进程内存。即使这样,攻击者也只能使用最新的密钥。您可能希望使用某些东西将键链接到数据,或者您必须针对每条记录强制使用键列表。如果您的日志带有时间戳、序列号或使用密钥 id 字段开始加密条目等,那么该记录可以像开始/停止时间一样简单。

无论您使用什么方法,在加密之前填充您的 IP。我看到,由于您更新了答案,因此提到了这一点,但这对于任何引用此内容的人来说绝对重要。这将阻止索引,但它也将防止任何“鸽子洞”问题以及相同的 IP 始终具有相同的加密输出。

你的方案是一个很好的解决方案。做得很好!

可能的性能优化。如果您需要一种提高效率的方法,那么有一些方法可以提高效率。例如,这里有一个。应用程序可以随机选择一个对称密钥K,用公钥加密K,然后在 K 下加密IP 地址,并将加密后的 IP 地址和K的加密值存储在数据库中。

以后导出日志的时候,如果想封禁某个IP,由于有私钥,可以恢复K对应的值,然后用K解密恢复IP地址,将该IP地址明文添加到禁令名单。

这如何提高性能?关键技巧是您可以为许多不同的 IP 地址重复使用相同的K值。当您启动时,它可以选择K,在公钥下对其进行加密,并缓存 K 的值和K加密现在它可以为许多日志条目重用它。如果需要,您可以定期清除缓存并创建新的K。(只需确保将K的缓存值仅存储在内存中,而不是存储在数据库中。)这样,您只需每隔一段时间进行一次公钥加密。每次你想记录一个新的 IP 地址,只需要在K下对其进行对称密钥加密,这应该是非常有效的。

为什么优化可能是不必要的。 也就是说,如果您正确选择公钥加密算法,即使您的基本方案也可能已经非常有效。例如,如果您使用公共指数 e=3 的 RSA 加密,那么加密速度非常快,并且您提出的方案可能足够快。

您的描述不完整,因为您没有告诉谁/什么将“根据加密形式验证 IP 地址”。从您的更新中,我猜您想要:

  • 能够记录传入的 IP 地址,这样攻击者获得对服务器文件的完全读取访问权限将无法重建记录的 IP 地址,但授权管理员(您)可以这样做;
  • 维护一组“禁止”IP 地址,可能包括范围,并且服务器必须能够将 IP 地址与该组匹配。

由于您(可以理解)不想在每次服务器重新启动时输入密码或插入密钥,因此您必须假设获得完整服务器文件的完全读取访问权限的攻击者知道服务器在重新启动后立即知道的所有内容。特别是,攻击者可以在他自己的机器上模拟服务器。由于这样的服务器可以决定一个给定的 IP 地址是否被禁止,攻击者可以通过他的模拟轻松获得相同的信息(毕竟只有 40 亿个 IPv4 地址)。推论:您最好将被禁止的(范围)地址保存在明文中,因为无论如何您都无法使其更安全。

对于日志记录使用,非对称加密看起来是正确的工具。适当的非对称加密已经包括随机填充(为了避免对数据本身进行详尽的搜索——实际上只有 40 亿左右的 IPv4 地址)。不过,RSA-4096 完全是矫枉过正。对于 IP 地址等低价值信息,1024 位就足够了(有关详细信息,请参阅此答案)。再一次,RSA-1024 意味着每个加密的 IP 地址将使用 128 个字节,您可能需要稍微优化一下,以节省空间。

例如,您可以使用Elliptic Curve Diffie-Hellman进行混合加密:加密 IPv4 地址,针对公钥执行 ECDH(与您的 RSA 密钥相同的原则:管理员单独保留私钥),然后使用生成的共享密钥用于加密 IPv4 地址。使用Format Preserving Encryption将 IPv4 地址加密为四个字节(例如,使用 Thorp shuffle,或者更简单的,使用 DH 密钥初始化的流密码)。对于“128 位安全性”,您需要 256 位椭圆曲线,然后可以将 ECDH 公钥编码为 32 个字节。加上加密的 IP 地址,每个地址有 36 个字节。

要进一步减少它,请应用@DW 的建议:在服务器启动时执行 ECDH 操作,并相互共享共享密钥的使用。您将有一张 ECDH 公钥表,该表增长缓慢(每次重新启动一个新条目),并且每个加密的 IP 地址只会引用要使用的密钥(32 位字段就足够了)。但请注意,在这种情况下,您必须注意随机化 IP 地址的对称加密。比如IP地址(4字节)用12字节随机填充,16字节用AES加密为一个块. 与公钥参考一起,这种较低的成本降低到每个 IP 大约 20 个字节。如果没有随机化,攻击者可以通过日志推断出哪些 IP 地址是重复的。由于该方案重用对称密钥,因此加密也必须更加小心(例如,像 RC4 这样的流密码将成为一个非常糟糕的主意)。

关于 CPU 性能:正如@DW 指出的那样,这不是问题。使用 ECDH,每个 IP 地址的时间低于 0.1 毫秒。RSA加密甚至会低于这样的成本。这就是为什么我专注于上面的空间性能,而不是 CPU。

好问题!

有 256^4 个可能的 IPv4 地址。如果您使用一种不会产生任何冲突的算法(一个 ip 产生一个唯一的哈希),您可以将其与鸽洞原理联系起来,在这种原理中,鸽洞(哈希)的数量与鸽子 (IP) 的数量相同或更多。您通常需要 >256^4 个鸽笼来存储加密的 IP 地址,并使用不会产生冲突的哈希算法。

攻击者可以轻松地对您的数据库执行暴力搜索,以查看与每个 IP 地址对应的哈希值,因为使用 256^4 个可能 IP 地址的低熵很容易找到一对一哈希值(即使有多次算法迭代)。如果不需要能够以 100% 的准确率将一个 ip 与数据库匹配,则一种方法可能是减少鸽子洞的数量。这也会在您选择的算法中引入哈希冲突。

因此,如果您使用 256^3(3 个字节)的散列大小,每个 IP 地址将有 256 个可能的冲突。

您没有在约束列表中提到错误碰撞的可能性,所以我不知道这对您是否有用。

您应该考虑的另一种方法是使用全盘加密和远程身份验证服务器。如果您使用 Windows 服务器,我相信您会发现使用PBConnex等预启动磁盘加密的解决方案就足够了。我目前不记得 linux 解决方案的名称,但我知道至少有一个。