简体   繁体   English

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

[英]How to store Credit Card info on iOS / Android in a PCI-compliant manner

I'm building a mobile app that accepts payments.我正在构建一个接受付款的移动应用程序。 The user enters their CC details, and the payment info is submitted to a retailer's POS system over HTTPS.用户输入他们的 CC 详细信息,然后付款信息通过 HTTPS 提交到零售商的 POS 系统。 The POS processes the payment directly and needs the actual credit card info to work, therefore we cannot use services like Stripe that will store the card, and give us back a token to process payments. POS 直接处理付款并需要实际的信用卡信息才能工作,因此我们不能使用像 Stripe 这样的服务来存储卡,并返回一个令牌来处理付款。

Because of the nature of the app, users will be making regular payments and so I want to store their CC info for convenience.由于应用程序的性质,用户将定期付款,因此为了方便起见,我想存储他们的抄送信息。 However this is not recurring billing, the user will be initiating the transaction at will.然而,这不是循环计费,用户将随意发起交易。 Therefore I don't need to keep CC centrally on a server and I'm considering storing individual cards on each user's device using this method:因此,我不需要将 CC 集中在服务器上,我正在考虑使用这种方法在每个用户的设备上存储单独的卡:

  • Collect CC number & expiration date收集 CC 编号和有效期
  • Encrypt it using AES256, using the CVC as key (CVC not stored)使用 AES256 加密,使用 CVC 作为密钥(未存储 CVC)
  • Then store the encrypted data in iOS keychain (or equivalent for Android)然后将加密数据存储在 iOS 钥匙串中(或等效于 Android)
  • To make a payment, (a) data is taken out of keychain, and为了付款,(a)从钥匙串中取出数据,并且
  • (b) the user must enter the CVC to decrypt the CC info (b) 用户必须输入 CVC 才能解密 CC 信息

The idea being, that if the user knows the CVC they likely possess the card anyway, hence they don't need to try hacking the device.这个想法是,如果用户知道 CVC,他们无论如何都可能拥有这张卡,因此他们不需要尝试破解设备。

For encryption, I'm considering using the RNCryptor lib .对于加密,我正在考虑使用RNCryptor lib One of its primary features is the automatic conversion of common passwords to cryptographically 'random' byte sequences of two 256-bit keys, for encryption and authentication.其主要功能之一是将通用密码自动转换为两个 256 位密钥的加密“随机”字节序列,以进行加密和验证。 The key stretching is implemented through 10k rounds of PBKDF2.密钥拉伸是通过 10k 轮 PBKDF2 实现的。 The implementation details are in the link, but in short:实现细节在链接中,但简而言之:

  • AES-256 encryption AES-256 加密
  • CBC mode CBC模式
  • Password stretching with PBKDF2使用 PBKDF2 进行密码拉伸
  • Password salting密码盐渍
  • Random IV随机IV
  • Encrypt-then-hash HMAC加密然后散列 HMAC


Questions:问题:

I don't understand the math well-enough to judge if seeding RNCryptor's key-stretching implementation with just the 3 CVC digits, would produce a statistically random enough key.我不太了解数学,无法判断仅用 3 个 CVC 数字播种 RNCryptor 的密钥拉伸实现是否会产生统计上足够随机的密钥。 I haven't been able to find any docs on what password specifications are required for RNCryptor to stay secure.我找不到任何关于 RNCryptor 需要什么密码规范才能保持安全的文档。 Any thoughts on that would be appreciated.对此的任何想法将不胜感激。 Using this lib is as simple as this:使用这个库就像这样简单:

// 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
}
// ...

When storying the AES256 encrypted CC info on iOS keychain (or droid equivalent), does it matter if there is no device lock passcode enabled?在 iOS 钥匙串(或等效机器人)上讲述AES256 加密的CC 信息时,是否启用设备锁定密码是否重要? My thinking is, the info is already AES256 encrypted, it could be stored on the device without keychain's encryption anyway?我的想法是,信息已经是 AES256 加密的,它可以存储在没有钥匙串加密的设备上吗?

What sections of PCI compliance are relevant in this case, given that there is no central server storing lots of CC numbers?鉴于没有中央服务器存储大量 CC 编号,在这种情况下 PCI 合规性的哪些部分是相关的? I tried reading the PCI specs but the docs are a maze to navigate :(我尝试阅读 PCI 规范,但文档是一个导航迷宫:(

  1. As Ebbe points out using just a CVC as the key, even derived from the CVC with PBKDF2 is not secure, there are only 1000 possible keys.正如 Ebbe 指出的那样,仅使用 CVC 作为密钥,即使使用 PBKDF2 从 CVC 派生也是不安全的,只有 1000 个可能的密钥。 Something else must be included in the key.密钥中必须包含其他内容。

  2. The date acts as a partial crib since it has a known format and limited values.日期充当部分婴儿床,因为它具有已知的格式和有限的值。 Also be careful not to include any other cribs such as field separators or field indicators.还要注意不要包含任何其他婴儿床,例如字段分隔符或字段指示器。

  3. The Credit Card Account Number Verification Check Digit is also a crib.信用卡帐号验证校验位也是一张婴儿床。

  4. In order for the Keychain to be secure the user must have entered a device lock passcode.为了使钥匙串安全,用户必须输入设备锁密码。

  5. Jailbroken and rooted devices must be avoided and that is difficult to determine.必须避免越狱和植根设备,这很难确定。

  6. As long as only the CC# and expiration date are saved, not any track 2 data and it is encrypted to PCI standards you should be OK.只要只保存 CC# 和到期日期,不保存任何轨道 2 数据,并且按照 PCI 标准加密,您应该没问题。

  7. See the PCI Point to Point Encryption Standard , it is free on the PCI site.请参阅 PCI 点对点加密标准,它在 PCI 站点上是免费的。 See Table 2, Application Developer.请参阅表 2,应用程序开发人员。

  8. Finally get a PCI auditor to review your scheme, this is just "best information" with the information provided and without a through evaluation.最后让 PCI 审核员审查您的计划,这只是提供的信息的“最佳信息”,没有通过评估。

Update based on the OP's comment:根据 OP 的评论更新:

There are 1000 CVCs to try.有 1000 个 CVC 可以尝试。 RNCryptor will take ~200ms per CVC try, that means all 1000 can be tried in ~4 minutes—ouch. RNCryptor 每次 CVC 尝试需要大约 200 毫秒,这意味着可以在大约 4 分钟内尝试所有 1000 次——哎哟。 RNCryptor has authentication so it will be immediacy known when the correct CVC is tried. RNCryptor 具有身份验证,因此在尝试正确的 CVC 时将立即知道。 This not not secure in the least and the authentication is working against you.这至少不安全,并且身份验证对您不利。

Without authentication then cribs need to be relied on.如果没有身份验证,则需要依赖婴儿床。 The first crib is the check digit, that will rule out ~900 CVCs leaving 100.第一个婴儿床是校验位,这将排除大约 900 个 CVC,剩下 100 个。

But is is is really worse depending the format that is encrypted.但实际上更糟,具体取决于加密的格式。 Decryption with an incorrect key will return essentially random bytes.使用不正确的密钥解密将返回基本上随机的字节。 If the CC# and date are a string the odds of the result being a digit string are virtually zip so again a correct decryption will be immediately known.如果 CC# 和日期是字符串,则结果是数字字符串的几率实际上是 zip,因此将立即知道正确的解密。 The best bet is to convert the CC# to a large integer and the date to a numeric day+year and encrypt this.最好的办法是将 CC# 转换为大整数,将日期转换为数字日 + 年并对其进行加密。 But even then there is the check digit crib and a valid date to use to validate the decryption.但即便如此,仍有校验位和有效日期用于验证解密。 It is actually more secure to not include the expiration date in the encryption.在加密中不包括到期日期实际上更安全。

In the end using a CVC as the key will not be secure, a much longer key is needed.最终使用 CVC 作为密钥将不安全,需要更长的密钥。

The Keychain does not protect its contents from the device owner and the device owner in reality is whoever has access, the passcode is what determined access and thus the device owner.钥匙串不保护其内容不受设备所有者的影响,实际上设备所有者就是有权访问的人,密码决定了访问权限,因此决定了设备所有者。

In case if you don't want to implement all the stuff by yourself, you can check VGSCollect SDKs for iOS and Android.如果您不想自己实现所有东西,可以查看适用于 iOS 和 Android 的 VGSCollect SDK。 SDK collects all the data in PCI scope. SDK 收集 PCI 范围内的所有数据。 All the encryption staff is done on their side, so you just get alias which you can use when sending payment request.所有加密人员都在他们身边完成,因此您只需获得别名,您可以在发送付款请求时使用该别名。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM