用于黑名单的正确信用卡加密

信息安全 加密 数据库 信用卡
2021-09-10 07:14:58

我有一个一般的加密问题。我在这里阅读了许多与加密相关的问题,但找不到任何专门解决我问题的问题。

这是假设场景:

  • 我将信用卡号存储在数据库中
  • 这些数字要么加密要么散列
  • 面向公众的应用程序检查客户请求是否包含黑名单上的信用卡信息
  • 攻击者已经破坏了数据库以及将信用卡添加到黑名单的能力。

攻击者可以在不知道加密密钥的情况下添加信用卡似乎是不现实的,但一种情况是他们向面向公众的应用程序发出请求,这似乎是欺诈,并且将让知道信用卡的应用程序自动将信用卡列入黑名单。加密密钥(这是对现实的极大简化)。

我想要一个提供以下内容的解决方案:
1)插入一张列入黑名单的信用卡,其工作时间为 O(log(n)) 或更少
2) 检查信用卡是否在黑名单上,工作时间为 O(log(n)) 或更少。例如,btree 索引可以提供 O(log(n)) 查找工作。
3) 使用加密或散列函数保护信用卡号码,这样如果数据被泄露,这些号码将无法使用。
4) 攻击者无法检查卡片是否在列表中,即使他们可以插入值并且可以看到加密/散列值。

我的问题与哈希信用卡号码用作指纹密切相关,但选择的答案说“当有新卡进来时,我们通过将其与哈希 + 加盐列进行比较来查找它。如果它与现有的列匹配,我们知道我们可以返回相同的唯一数字标识符”。此解决方案是不可接受的,因为这需要 O(n) 查找时间。换句话说,我需要检查黑名单中的每一行以查看该号码是否在列表中。

第一个提出的解决方案:典型的懒惰程序员回答
不要加密。无论如何,这些只是糟糕的欺诈数字。
失败:仅仅因为我们认为这些是坏客户的,并不意味着我们应该公开这些数字。这也不意味着我们在 100% 的时间里正确地将其列入黑名单,此外,即使客户是坏人并进行欺诈,我们仍然无权公开他们的号码。

第二个建议的解决方案:不加盐散列信用卡
这提供了快速插入和快速查找。只需再次对卡号进行哈希处理,然后检查哈希值是否在列表中。
失败:问题是攻击者可以通过简单地散列随机卡号并检查该值是否在列表中来暴力破解信用卡。即使使用慢速散列算法也是一个问题,因为有效卡号的空间很小,并且每个散列检查黑名单上可能有数百万行(请记住,这是一种假设情况。我实际上并没有存储数百万个信用卡号) .

第三个建议的解决方案:为每一行使用唯一盐的散列
这个解决方案可以很容易地用 crypt(3) 或类似的东西提供。它无缝地将盐存储在散列值中。现在,如果攻击者试图暴力破解数字,他们也将不得不暴力破解盐。这使得攻击不可行。失败:现在执行黑名单查找需要 O(n) 的工作。我们需要在每一行上调用慢散列函数,性能变得无法接受。

第四种建议的解决方案:使用存储在数据库外部的全局盐(HMAC)
进行哈希现在攻击者需要使用面向公众的 api 来执行哈希操作,而不是每秒执行数百万次离线哈希。他们不能执行离线攻击的原因是存储在数据库之外的全局盐足够长,盐不能被暴力破解。
失败:仍然存在这样一个事实,即插入检查可能存在数百万行并且信用卡状态空间很小。攻击者每天可以执行 1000 个请求,并将导致重复的请求记录在数据库中。重复项是已经在黑名单中的信用卡号

第五个建议的解决方案:通过默默无闻的
安全性失败:这不是真正的安全性。这很诱人,但假设攻击者已经破坏了数据库,那么他们很有可能是公司内部的管理员,并且可以访问我们实施的任何解决方案和算法。

第六个建议的解决方案:制作另一个较小的桌子。
将数字列入黑名单时,将带有盐的完整数字的散列存储在表 1 中,并将表 2 中最后 4 位数字的散列存储在不带盐的情况下(删除重复项)。当检查一个号码是否被列入黑名单时,检查表2。大多数情况下不会命中,检查速度很快。在极少数情况下,会出现命中,然后对表 1 进行缓慢检查。
失败:如果我存储了数千条记录,则很可能最后 4 位数字存在于此列表中。4 位数字是 10000 个唯一的组合,并且有 10000 个卡片条目,很有可能会出现命中,从而导致检查缓慢。此外,攻击者将知道表 2 中的条目将在表 1 中至少有一个匹配项。他们可以仅用 10000 个请求对表 1 进行暴力破解,现在他们已经大大减少了表 1 的搜索空间。帖子引用了 100,000,000 作为可能可能的信用卡号空间大小。表 2 会有效地将这个空间减少到 100,000,000/10,000 = 10,000。这意味着反转一个哈希的时间大约是我的应用程序检查表 1 所花费的时间(表 1 中的 10,000 行意味着 10,000 个慢速散列,而蛮力也将是 10,000 个慢速散列)

所有解决方案也适用于加密而不是散列。加密的好处是现在攻击者必须对面向公众的应用程序进行在线攻击。这仍然不能解决建议的解决方案 4 中指出的问题。此外,加密而不是散列的风险在于,如果加密密钥被泄露,攻击者会立即拥有所有纯文本值。至少通过散列,他们只能暴力破解列表中的一些卡号。

我还研究了标记化https://securosis.com/assets/library/reports/Securosis_Understanding_DBEncryption.V_.1_.pdf并且存在同样的问题,只是在重复的令牌而不是重复的哈希中。

请注意,我想要比 PCI-DSS 合规性更强的东西。解决方案 2 在技术上符合 PCI_DSS,因为不需要盐 https://www.pcisecuritystandards.org/documents/PCI_DSS_v3.pdf(PDF链接)

对不起,很长的帖子。有谁知道这是否可能?

4个回答

这是一个相当高的要求,OP,我认为不可能完美地做到这一点。尽管如此,这里有几个想法。

攻击者无法检查卡是否在列表中,即使他们可以插入值并可以看到加密/散列值。

答案是插入误报。如果要将卡列入黑名单,请计算由 PAN 组成的哈希(或哈希 + crypt——见下文)。如果不是,则将哈希计算为 PAN + nonce。在这两种情况下,插入一条记录。要检查卡是否被列入黑名单,请在没有随机数的情况下重新组合哈希并检查它。

这样,黑客可以看到插入了一条记录,但插入本身并没有告诉他任何信息。

使用加密或散列函数保护信用卡号码,这样如果数据被泄露,这些号码将无法使用。

散列 PAN + 长的、系统范围的加密辣椒(秘密盐)

辣椒会增加足够的熵,以使不知道密钥的暴力破解成为不可能。将辣椒存储在数据库之外。

要检查匹配,请在感兴趣的 PAN 上执行散列,然后搜索表。因为这些秘密都是系统范围的,所以您应该能够利用索引,包括为您提供您正在寻找的 O(log(n)) 性能的漂亮 B-tree 索引。

我看到你的问题最大的问题是:Have the credit card numbers secured with either encryption or a hashing function so that if the data is compromised the numbers will not be usable.

这是一个问题,因为正如@Bobson在评论中所说Even hashing credit card numbers is problematic. Given the restricted nature of valid card numbers, it's likely that there's only one valid number which hashes to a given hash.

起初我以为这是因为搜索空间被限制在 [0-9]{15-16} 或 1.11 x 10^16 ... 这有点糟糕,但每个卡号的离线攻击率为 1.29 天。 ..它不是世界末日坏。但在做了更多研究后,我发现问题实际上比这更糟糕。

您卡上的第一个数字:如果以 3 开头,则为 American Express、Diner's Club 或 Carte Blanche;4 个保留给 Visa,5 个保留给 MasterCard,6 个保留给 Discover。接下来的五位数字将指示发卡机构,例如银行或信用合作社,以及信用卡的类型。因此,例如,所有 Citi AAdvantage Executive MasterCard 都将以 546616 开头,其中 5 代表 MasterCard,46616 代表 Citi,并且它是美国航空公司 AAdvantage Executive 卡之一。剩下的 16 位数字(或 15 位,在美国运通的情况下)代表持卡人的帐号以及一个或多个“校验位”。来源

对于 16 位数字,从左边的第一个数字开始,然后将卡片上的每个交替数字加倍。(对于 15 位数字,从左数第二个数字开始。)添加任何两位数,使它们减少为一位数。(例如,如果其中一个数字是 8,它会加倍为 16,然后将 1 + 6 相加得到 7。)接下来,将它们与未加倍的交替数字相加。如果您得到的总数能被 10 整除,则信用卡号可能有效。来源

因此,这意味着在数字 1222-2233-4444-4444 中,您的搜索空间仅略大于 [0-9]{8},这意味着:

  • 每张卡 1.29 天 - 假设每秒有一千个哈希(在线攻击)
  • 每张卡 1.11 毫秒 - 假设每秒有一千亿个哈希(离线攻击)

来源

当您考虑实际流通的卡片数量时,这个问题会变得更糟

Type of Credit Card 2000    2003    2007    2008    2010    2012
Visa                 255     283     321     304     240     261
Mastercard           200     267     279     260     171     174
Store                597     521     546     539     318     455
Oil Company           98      86      73      65      35      60
Discover              50      54      57      58      55      59
American Express      33      36      52      54      49      52
Other                192     185     166     160     124     106
Total              1,425   1,432   1,494   1,440     992   1,167

*cards in millions 

来源

这意味着,除非您有一个额外的熵源,它没有存储在数据库中(又名不是盐),也没有在程序中进行哈希(又名不是胡椒)除了卡号本身......将信用卡哈希存储在一切都是不可取的。

但是,如果黑客可以访问我的实时数据库并能够任意向其中输入信息怎么办......

您可以(实际上应该)争辩说,如果有人可以向您的数据库添加内容,那么您的问题比黑名单的安全性要大 - 让我们从权限提升、管理员超级用户黑客等开始(添加/删除卡片要容易得多)黑名单通过您的管理界面而不是通过您的数据库)。

如果我们谈论的是您的数据库的离线转储被盗,那么您有责任确保 PAN 的安全。根据 PCI DSS 委员会在要求 3:保护PCI DSS 的“要求和安全评估程序”中存储的持卡人数据中定义的“足够好 PAN 保管”:

3.4 使用以下任何一种方法使 PAN 在任何存储的地方(包括便携式数字媒体、备份媒体和日志中)都无法读取:

  • 基于强密码学的单向哈希,(哈希必须是整个 PAN)
  • 截断(散列不能用于替换 PAN 的截断段)
  • 索引令牌和衬垫(衬垫必须安全存放)
  • 具有相关密钥管理流程和程序的强大密码学。

注意:如果恶意个人可以访问 PAN 的截断和散列版本,则重建原始 PAN 数据是一项相对微不足道的工作。如果实体环境中存在同一 PAN 的散列和截断版本,则必须采取额外的控制措施,以确保散列和截断版本无法关联以重建原始 PAN。

不过,我会争辩说,底部的注释暗示 PCI DSS 委员会希望人们不要给他们的哈希值加盐。稍后阅读有关哈希及其安全性的更多信息。

请注意,根据 PCI DSS 标准,我在此处列出的所有选项都“足够好”,具有不同的可用性和偏执程度。

选项 1:仅使用屏蔽的 PAN

(并且掩码的 PAN 是 PAN 的前 6 个和后 4 个字符)

使用蒙面的 PAN 将其列入黑名单。在我的历史中,我曾见过珍贵的小卡片,其中 2 位用户使用相同的蒙面 PAN 和不同的完整 PAN,也许它很少会成为帮助台而不是编程问题。

选项 2:使用掩码 PAN和加密 PAN

如果您想防止这种情况发生,请使用蒙版 pan 来获取一些行(通常为 1,几乎从不 2),然后与盐渍散列 PAN 进行比较,全局盐就可以了。但此时您也可以使用加密的 PAN(解密和比较),因为 99.99% 的时间您将仅与 1 条记录进行比较。

  • 问:但这对我不起作用,我蒙面的 PAN 只是 Luhn 数字!我能做什么?
  • A:那么抱歉,显然你不能使用这种方法,只要记住 PCI 委员会认为前 6 和后 4 是“掩码 PAN”。你仍然可以使用散列,继续阅读

选项 3:使用散列 PAN

不,您不需要检查 O(n) 记录来进行验证。使用表级胡椒和数据库索引并放弃盐。

哈希安全性完全是另一回事,但请记住:

  1. 表级的椒应该够用了,盐用处不大,因为它会被数据库偷走
  2. 多次重复执行散列操作,这种做法称为拉伸
  3. 通过 HSM 存储和使用辣椒

看看这个实现给你一个大致的想法。

您的 HSM 是否允许这样的方案?硬件 HSM 对摘要的支持通常很差,因此您可以使用普通的 3DES/AES 来做同样的事情。

  • 问:我知道这种方法可能比我的管理员密码的安全性更强,但我仍然不确定,毕竟它是软件存储的辣椒,而且它们是全表的,感觉不安全
  • 答:好的 - 但请记住 -这就是 PAN 辣椒的用途- 这种方法超出了 PCI DSS 的要求 - 而行级盐是使彩虹攻击更难的东西,它们也是你与哈希一起窃取的东西他们自己,因此与未存储在数据库中的东西相比,它们的安全性没有实际意义——比如数据库级辣椒——但是好的,继续阅读,您可以通过将 HSM 应用于问题来扩展这种方法

选项 3b:散列 + 加密 PAN

在 ECB 模式下使用 3DES 或 AES 密码(我在本节中将它们称为“DES”,不要被此混淆)或在 CBC 模式下使用固定 IV。为了通过模糊性增加安全性,您可以在 IV 中编码某些内容,例如 PAN 的一部分,或者更强大的 - 另一种只能通过 HSM 访问的密码(ECB 加密的 PAN 或其派生被认为是一个不错的 IV 候选者)。

使用与之前描述的相同的技术,如我提供的代码示例中所示 - 使用全局胡椒 - 带或不带摘要 & 在 DES 下 - 这将确保如果攻击者逃跑了您的数据库、您的代码库和您的服务器设置,如果不首先破坏 DES,他将无法启动彩虹攻击,这是“不可能的”,因为 DES 密钥在 HSM 中。

请注意,在这种情况下,ECB 和固定 IV CBC “足够好”,因为胡椒和散列材料的潜在随机性。

  • 问:但我还是不开心,因为......
  • 答:嗯..继续阅读

但最终...

我很确定你不能让这个方案比这更安全,同时仍然保持它应该做的功能。

安全性和可用性是两个截然相反的东西,不要完全偏执模式,要聪明。到目前为止,根据我的经验,完全偏执模式可能会以有趣的方式适得其反:

  • 我已经可以想象,在您的机构中,当您正在寻找完美的解决方案时,一些懒惰的程序员在 6 个月前在数据库中实施了明确的 PAN,因为管理层在大喊大叫——这可能不像你一直在没有黑名单的情况下运行——我已经看到这种情况发生在一家全球电子钱包提供商身上——如果这是你的情况——你并不孤单
  • 一家军事情报机构和一家拥有强密码的银行——密码分别写在键盘背面的便利贴上和桌面上的“not passwords.txt”文件中
  • 一家超级 uber-PCI-DSS 在欧盟的这家安全的国家银行中一无所获到建筑物的所有区域和所有计算机,因为安全软件的“第三方”模块与“linux驱动程序”不兼容,无论这意味着什么
  • 一个超级安全的 PCI DSS 环境和一条从 CSO “隐藏”的“魔法电缆”,从安全盒中伸出并进入路由器,因为协议没有预见到抽屉有限的安全柜中的大规模硬件迁移
  • 与最后一点相同的机构,软件中的一个错误,其中 10-20 个 PAN 的前 8 个字符出现在安全环境中的日志中(按 PCI 标准)。有人会加密日志,但 CSO 辩称这与 PCI 规范中的某些“易用性条款”相冲突,并坚持联系卡的发行商将卡列入黑名单并重新发行,因为“它们已被泄露” ,同时也是合作伙伴的银行的强烈反对是可以理解的,这位 CSO 最终失去了工作
  • PIN 加密,保护与克隆 Visa/MC 卡受 ECB 的 2 长 DES 密钥保护,从未破解过密码,但人们将 PIN 写在卡上,因为它们很难记住,而美国仍然普遍使用磁条,因为 EMV难以实施
  • Mifare 卡,单一长度的 DES 加密,100 亿个芯片,1.5 亿个读卡器,最近才在 AES 成功违反密钥协商方案后才进行扩展,该方案也可能是由孩子编写的(一方赚了一半连接到另一方的半密钥而不是适当的全长异或方案的密钥 - 并且当主密钥加载到卡中时的初始密钥交换仍然是具有预定义 000..0000 密钥的 DES) -被认为是安全的
  • 让我们记住https://xkcd.com/538/ :D

所以,是的,如果你想在安全方面比教皇更圣洁,你要自己承担风险,不要成为原教旨主义者,要聪明。将您的精力集中在最重要的地方保护您的系统 -黑名单几乎可以肯定不是

我猜这是因为通常当您拥有黑名单时,您已经为交易、风险规则等设置了“安全卡查找机制”,而且问题通常在几个月前就已解决。这不是这里的情况。

PS 获取一个在线 API 并尝试对 10.000 个卡号进行暴力“扫描”(1 美元授权),看看处理器会告诉你什么。对此有制衡,请阅读:

  • “VISA:全球收购方风险标准”
  • 《VISA:收单机构全球品牌保护计划指南》

了解更多关于它们的信息。

我认为这是您应该重新解决问题的情况。

无法绕过有效 PAN 的小得可笑的空间。您所有的安全性都来自熵(盐)和工作(迭代),而您是免费要求的。你不会免费得到它。

加快它的唯一方法是尝试通过制作一种“预过滤器”来确保您在大多数时候不必进行这些计算。所有可能的预过滤器都是等价的,因为它们是概率性的,不能保证复杂性。所有这些预过滤器仅返回“可能在集合中”和“不在集合中”。他们泄露了这些数据。你无法解决这个问题。

像布隆过滤器这样更简单、更快的预过滤器不会为您提供有界的搜索集,即使它具有 O(1) 的快速运行时间。提议的解决方案 #6 中的两表方法为您提供了要搜索的确切集合,但更复杂 - o(log(n))。

但是等等 - 解决方案 #6 如何等同于布隆过滤器?嗯,布隆过滤器返回“0 搜索”或“n 搜索”。它告诉你“不在片场”或“可能在片场”。我们从两表解决方案中得到了什么?

存在两个表:一个带有屏蔽 PAN(前 6 位和后 4 位),使用全局盐进行散列,其中每个记录指向具有完整 PAN 的完整表中的行,使用唯一盐进行强散列。您对传入的 PAN 的屏蔽形式进行哈希处理,并对预过滤器表进行 o(log(n)) 搜索。

现在我们已经完成了 o(log(n)) 搜索,我们最终得到了 0-n 个可能的哈希值进行比较,并且更小的数字更有可能。匹配数 0 是“绝对不在集合中”,而 1+ 是“可能在集合中”。然后,您仍然需要进行(可能很少)一些困难的计算来检查强哈希。

无论是布隆过滤器还是 o(log(n)) 两表方法,或任何其他方法,所有工作都以某种方式完成。你不能欺骗它。你可以微调它,但你不能欺骗它。

任何其他方法都与此等效。通过简单的预查找来减少熵意味着减少问题空间,然后您尝试将其映射到更大的问题空间,这意味着您正在处理概率。

从信息论的角度来看,这些只是事实。所以,我建议你重新解决问题,而不是解决方案。