Как хранить информацию о кредитной карте на iOS / Android в соответствии с PCI
Я создаю мобильное приложение, которое принимает платежи. Пользователь вводит свои данные CC, и информация о платеже передается в POS-систему розничного продавца по протоколу HTTPS. POS обрабатывает платеж напрямую и нуждается в действительной информации о кредитной карте, поэтому мы не можем использовать такие службы, как Stripe, которые будут хранить карту и возвращать нам токен для обработки платежей.
Из-за характера приложения пользователи будут делать регулярные платежи, и поэтому для удобства я хочу сохранить их информацию о CC. Однако это не повторяющийся биллинг, пользователь будет инициировать транзакцию по желанию. Поэтому мне не нужно централизованно хранить CC на сервере, и я рассматриваю возможность хранения отдельных карт на устройстве каждого пользователя, используя этот метод:
- Собрать номер CC и срок годности
- Зашифруйте его, используя AES256, используя CVC в качестве ключа (CVC не сохраняется)
- Затем сохраните зашифрованные данные в брелок iOS (или эквивалент для Android)
- Для осуществления платежа (а) данные берутся из цепочки для ключей, и
- (б) пользователь должен ввести CVC для расшифровки информации CC
Идея заключается в том, что если пользователь знает CVC, он, вероятно, в любом случае владеет картой, поэтому ему не нужно пытаться взломать устройство.
Для шифрования я рассматриваю возможность использования библиотеки RNCryptor. Одной из его основных функций является автоматическое преобразование общих паролей в криптографически "случайные" байтовые последовательности двух 256-битных ключей для шифрования и аутентификации. Ключ протягивается через 10 тыс. Раундов PBKDF2. Детали реализации находятся в ссылке, но вкратце:
- Шифрование AES-256
- Режим CBC
- Растяжение пароля с помощью PBKDF2
- Посол пароля
- Случайный IV
- Зашифровать то хэш HMAC
Вопросы:
Я не достаточно хорошо понимаю математику, чтобы судить, даст ли реализация реализации растяжения ключа RNCryptor только с 3 цифрами CVC достаточно статистически случайный ключ. Я не смог найти никаких документов о том, какие спецификации паролей требуются для обеспечения безопасности RNCryptor. Любые мысли по этому поводу будут оценены. Использовать эту библиотеку так же просто, как это:
// 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
}
// ...
При написании зашифрованной информации CC AES256 на связке ключей iOS (или эквивалент дроида), имеет ли значение, если не включен пароль блокировки устройства? Я думаю, что информация уже зашифрована AES256, она может храниться на устройстве без шифрования брелка в любом случае?
Какие разделы соответствия PCI актуальны в этом случае, учитывая, что нет центрального сервера, хранящего много номеров CC? Я пытался читать спецификации PCI, но документы - это лабиринт для навигации:(
1 ответ
Поскольку Эббе указывает, что в качестве ключа используется только CVC, даже полученный из CVC с PBKDF2 небезопасен, существует только 1000 возможных ключей. Что-то еще должно быть включено в ключ.
Дата действует как частичная шпаргалка, поскольку она имеет известный формат и ограниченные значения. Также будьте осторожны, чтобы не включать какие-либо другие шпаргалки, такие как разделители полей или указатели полей.
Контрольная цифра проверки номера счета кредитной карты также является детской кроваткой.
Для того чтобы связка ключей была надежной, пользователь должен ввести код блокировки устройства.
Необходимо избегать взломанных и рутированных устройств, и это трудно определить.
Пока сохраняются только CC# и дата истечения срока действия, а не данные дорожки 2 и они зашифрованы в соответствии со стандартами PCI, все будет в порядке.
См. PCI Point to Point Encryption Standard, он бесплатный на сайте PCI. Смотрите Таблицу 2, Разработчик приложений.
Наконец, попросите аудитора PCI проверить вашу схему, это просто "лучшая информация" с предоставленной информацией и без сквозной оценки.
Обновление на основе комментария ОП:
Есть 1000 CVC, чтобы попробовать. RNCryptor потребует ~200 мс за попытку CVC, что означает, что все 1000 могут быть опробованы за ~4 минуты - ой. RNCryptor имеет аутентификацию, поэтому сразу же станет известно, когда будет выполнен правильный CVC. Это небезопасно, и аутентификация работает против вас.
Без аутентификации тогда можно полагаться на шпаргалки. Первая шпаргалка - контрольная цифра, которая исключает ~900 CVC, оставляя 100.
Но это действительно хуже в зависимости от формата, который зашифрован. Расшифровка с неверным ключом вернет по существу случайные байты. Если CC# и дата являются строкой, то шансы на результат, представляющие собой строку цифр, фактически равны zip, поэтому снова правильное дешифрование будет немедленно известно. Лучше всего преобразовать CC# в большое целое число, а дату в числовой день + год и зашифровать это. Но даже в этом случае есть шпаргалка с контрольной цифрой и действительная дата, которую можно использовать для подтверждения расшифровки. На самом деле более безопасно не включать дату истечения срока действия в шифрование.
В конце концов, использование CVC в качестве ключа не будет безопасным, потребуется гораздо более длинный ключ.
Цепочка для ключей не защищает свое содержимое от владельца устройства, и на самом деле владельцем устройства является тот, кто имеет доступ, пароль доступа определяет доступ и, следовательно, владельца устройства.
Если вы не хотите реализовывать все самостоятельно, вы можете проверить SDK VGSCollect для iOS и Android. SDK собирает все данные в области PCI. Весь персонал шифрования выполняется на их стороне, поэтому вы просто получаете псевдоним, который вы можете использовать при отправке запроса на оплату.