Обеспечение соответствия мобильного приложения требованиям PCI DSS (платёжные данные)
PCI DSS v4.0 — стандарт Совета по стандартам безопасности платёжных карт, обязательный для любого ПО, которое передаёт, обрабатывает или хранит данные держателей карт. Для мобильных приложений критичен раздел 6 (Secure Development) и раздел 4 (Encryption in Transit). Без соответствия крупный эквайер просто не выдаст возможность прямого эквайринга — придётся работать только через iFrame-решения.
Что конкретно нарушают большинство приложений
Хранение PAN в логах. Разработчик добавляет Log.d("Payment", "Card: $cardNumber") для отладки. Попадает в logcat, который читается любым другим приложением на незащищённом Android устройстве. PCI DSS требование 3.3: PAN не должен отображаться в логах в незашифрованном виде.
Скриншоты экрана ввода карты. Android по умолчанию позволяет снимать скриншоты любого Activity. На экране ввода реквизитов это критичная уязвимость:
// Должно быть на любом экране с карточными данными
window.setFlags(
WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE
)
На iOS аналогично — нужно перекрывать UI при переходе в background:
func applicationWillResignActive(_ application: UIApplication) {
// Добавить overlay поверх sensitive-контента
coverSensitiveContent()
}
Certificate pinning отсутствует. Трафик к платёжному серверу перехватывается Charles Proxy или mitmproxy без каких-либо препятствий. PCI DSS 6.5.4 требует защиты от атак типа man-in-the-middle.
// iOS: URLSession с кастомным делегатом для certificate pinning
class PinnedURLSessionDelegate: NSObject, URLSessionDelegate {
func urlSession(
_ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
) {
guard
let serverTrust = challenge.protectionSpace.serverTrust,
let certificate = SecTrustGetCertificateAtIndex(serverTrust, 0)
else {
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
let pinnedHash = "sha256/AbCdEfGhIjKlMnOpQrStUvWxYz123456789="
let serverHash = certificateHash(certificate)
if serverHash == pinnedHash {
completionHandler(.useCredential, URLCredential(trust: serverTrust))
} else {
completionHandler(.cancelAuthenticationChallenge, nil)
}
}
}
Root/Jailbreak detection. PCI DSS 6.4.3 рекомендует (но не обязывает) обнаруживать скомпрометированные устройства. На практике крупные эквайеры требуют это через SDK. Используют комбинацию: проверка наличия /bin/bash, Cydia, su-команды, несовпадение подписи процесса.
Tokenization вместо хранения PAN
Главный принцип PCI DSS для мобильных приложений — не хранить PAN вообще. Приложение работает с токеном, который выдаёт платёжный провайдер. Stripe называет это PaymentMethod, CloudPayments — Token, ЮKassa — payment_method_id.
// Stripe: никогда не видим PAN в коде
import StripePaymentSheet
var configuration = PaymentSheet.Configuration()
configuration.merchantDisplayName = "YourShop"
PaymentSheet.FlowController.create(
paymentIntentClientSecret: clientSecret,
configuration: configuration
) { [weak self] result in
switch result {
case .success(let flowController):
self?.paymentSheetFlowController = flowController
case .failure(let error):
// обрабатываем
}
}
Карточные данные уходят напрямую в Stripe SDK → Stripe токенизирует → приложение получает paymentMethodId. PAN никогда не касается вашего сервера — это снижает scope PCI DSS с SAQ D до SAQ A.
Audit trail и логирование
PCI DSS требование 10: логировать доступ к cardholder data environment. Для мобильного приложения это означает:
- Логировать каждый успешный/неуспешный платёж с timestamp, userId, замаскированным PAN (первые 6 + последние 4 цифры), статусом
- Логи хранить не менее 12 месяцев, из которых 3 — немедленно доступны
- Защитить логи от модификации (append-only storage)
Маскировка PAN в логах:
fun maskPan(pan: String): String {
return pan.take(6) + "*".repeat(pan.length - 10) + pan.takeLast(4)
}
// "4111111111111111" → "411111******1111"
Процесс оценки и работы
Полноценная PCI DSS оценка для мобильного приложения включает несколько этапов.
Scoping — определяем, касается ли мобильное приложение cardholder data environment напрямую или через провайдера (Stripe, CloudPayments). Если через провайдера — scope значительно меньше.
Gap-анализ — проверяем 12 требований стандарта применительно к коду, инфраструктуре, процессам. Типичные находки: plaintext logs, отсутствие certificate pinning, missing FLAG_SECURE, недостаточное шифрование local storage.
Remediation — исправление найденных уязвимостей: внедрение certificate pinning, перевод хранилища на Keychain/Keystore, настройка obfuscation, добавление root detection.
Penetration testing — PCI DSS 11.3 требует pen-тест минимум раз в год и после значимых изменений. Для мобильных приложений это статический анализ (MobSF, Checkmarx), динамический анализ с прокси, тестирование binary reversing.
ASV scanning — если приложение взаимодействует с сервером напрямую, требуется квартальное сканирование публичных IP через Approved Scanning Vendor.
Ориентиры по срокам
Gap-анализ и итоговый отчёт — 3–5 дней. Remediation — зависит от количества и сложности находок, обычно 1–3 недели. Подготовка к QSA-аудиту — дополнительно.
Стоимость рассчитывается индивидуально после анализа требований и текущего состояния кодовой базы.







