如何以符合PCI标准的方式在iOS / Android上存储信用卡信息

时间:2017-04-13 20:57:50

标签: encryption payment pci-compliance pci-dss rncryptor

我正在构建一个接受付款的移动应用。用户输入他们的CC详细信息,并通过HTTPS将支付信息提交给零售商的POS系统。 POS直接处理付款并需要实际的信用卡信息才能工作,因此我们不能使用Stripe这样的服务来存储卡,并给我们一个代币来处理付款。

由于应用程序的性质,用户将定期付款,因此我希望存储他们的CC信息以方便使用。然而,这不是重复计费,用户将随意启动交易。因此,我不需要将CC集中保存在服务器上,而且我正在考虑使用这种方法在每个用户的设备上存储个人卡:

  • 收集CC号码&到期日
  • 使用AES256加密,使用CVC作为密钥(CVC未存储)
  • 然后将加密数据存储在iOS钥匙串(或Android等效产品)
  • 要付款,(a)从钥匙串中取出数据,
  • (b)用户必须输入CVC才能解密CC信息

这个想法是,如果用户知道CVC他们可能还拥有该卡,因此他们不需要尝试攻击该设备。

对于加密,我正在考虑使用RNCryptor lib。其主要功能之一是将公共密码自动转换为两个256位密钥的加密“随机”字节序列,以进行加密和身份验证。关键拉伸通过10k轮PBKDF2实现。实现细节在链接中,但简而言之:

  • AES-256加密
  • CBC模式
  • 使用PBKDF2进行密码拉伸
  • 密码腌制
  • Random IV
  • 加密 - 然后哈希HMAC


的问题:

我不太了解数学,足以判断只用3个CVC数字播种RNCryptor的键扩展实现是否会产生统计上足够随机的密钥。我无法找到任何有关RNCryptor保持安全所需的密码规范的文档。对此的任何想法将不胜感激。使用这个lib就像这样简单:

// Encryption
NSData *data = ...
NSString *password = @"Secret password";
NSData *ciphertext = [RNCryptor encryptData:data password:password];

// Decryption
NSError *error = nil;
NSData *plaintext = [RNCryptor decryptData:ciphertext password:password error:&error];
if (error != nil) {
    NSLog(@"ERROR:%@", error);
    return
}
// ...

在iOS钥匙串(或droid等效版)上讲述 AES256加密 CC信息时,如果没有启用设备锁定密码,这是否重要?我的想法是,信息已经加密了AES256,它可以存储在没有钥匙串加密的设备上吗?

在这种情况下,PCI合规性的哪些部分是相关的,因为没有中央服务器存储大量的CC号码?我尝试阅读PCI规范,但文档是导航的迷宫:(

2 个答案:

答案 0 :(得分:3)

  1. 正如Ebbe指出只使用CVC作为密钥,即使从带有PBKDF2的CVC派生也不安全,只有1000个可能的密钥。密钥中必须包含其他内容。

  2. 日期充当部分婴儿床,因为它具有已知格式和有限值。另外,请注意不要包括任何其他婴儿床,如野外分离器或现场指示器。

  3. 信用卡帐号验证校验位也是婴儿床。

  4. 为了使Keychain安全,用户必须输入设备锁密码。

  5. 必须避免使用越狱和植根设备,这很难确定。

  6. 只要保存CC#和失效日期,而不是任何跟踪2数据,并且加密到PCI标准,您应该没问题。

  7. 请参阅PCI Point to Point Encryption Standard,它在PCI站点上是免费的。参见表2,Application Developer。

  8. 最后请PCI审核员审核您的方案,这只是提供信息的“最佳信息”,无需通过评估。

  9.   

    根据OP的评论进行更新:

    有1000个CVC可供尝试。 RNCryptor每次CVC尝试需要大约200ms,这意味着所有1000个都可以在~4分钟内完成。 RNCryptor具有身份验证,因此在尝试使用正确的CVC时,它将立即知晓。这至少不安全,身份验证对您不利。

    如果没有身份验证,则需要依赖婴儿床。第一个婴儿床是校验位,排除了约900个CVC,100个。

    但是根据加密的格式确实更糟糕。使用不正确的密钥解密将返回基本上随机的字节。如果CC#和日期是一个字符串,结果是数字字符串的几率实际上是拉链,那么将立即知道正确的解密。最好的办法是将CC#转换为一个大整数,将日期转换为数字日+年并加密。但即使这样,也有支票数字婴儿床和用于验证解密的有效日期。在加密中不包括截止日期实际上更安全。

    最后使用CVC作为密钥将不安全,需要更长的密钥。

    钥匙串不保护其内容不受设备所有者的影响,而设备所有者实际上是有权访问的人,密码是确定的访问权限,因此是设备所有者。

答案 1 :(得分:0)

如果您不想自己实现所有功能,可以检查适用于iOS和Android的VGSCollect SDK。 SDK收集PCI范围内的所有数据。所有的加密工作人员都在他们身边完成,因此您只需获取别名即可在发送付款请求时使用。