Статья Уязвимости банковских API: методология пентеста от разведки до эксплуатации

Золотая монета, разрезанная пополам на чёрной поверхности. На срезе видны гравированные пути API-эндпоинтов и надписи с идентификаторами уязвимостей, резкий свет подчёркивает детали.


На пентесте API одного банка мы подменили account_id в GET-запросе к /api/v2/accounts/{id}/balance - и получили баланс чужого счёта. Без повышения привилегий, без обхода WAF, без единого алерта в SIEM. Банк прошёл PCI DSS аудит за месяц до этого, использовал OAuth 2.0 и выставлял API Gateway от крупного вендора. Вся защита разбилась о один параметр в URL. Один. Параметр.

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

Почему банковские API - особая поверхность атаки​

Финансовые API отличаются от любых других одним свойством: успешная эксплуатация - это прямой вывод средств. Не утечка данных, не дефейс - конкретные деньги на конкретном счёте. Отсюда и профиль атакующих (организованные группы, а не скрипт-кидди), и последствия (чарджбэки, регуляторные штрафы, отзыв лицензии).

По данным Akamai и Traceable, финансовый сектор - одна из наиболее атакуемых отраслей по API-вектору. Причина не в том, что банковские API хуже защищены, а в том, что payoff от успешного эксплойта прямой и немедленный. Опросы финтех-организаций рисуют мрачную картину: значительная доля компаний уже сталкивалась с утечками через API, тестируется малая часть эндпоинтов, а предотвращать организации способны мизерную долю атак. В России, по оценкам «Солара», количество событий, классифицированных как API-атаки, за 2024 год выросло в разы.

Ещё один фактор - PSD2 и open banking. Банки обязаны предоставлять доступ к API третьим сторонам, что расширяет поверхность атаки кратно.

Уязвимы не только сами банковские API, но и инструменты управления доступом к ним. Свежий пример - CVE-2024-12356 в BeyondTrust Privileged Remote Access и Remote Support: критическая command injection (CWE-77, CVSS 9.8, вектор AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) позволяла неаутентифицированному атакующему выполнять команды на сервере. Уязвимость в CISA KEV как активно эксплуатируемая. BeyondTrust - стандартный инструмент привилегированного доступа в банках, и компрометация такого компонента - это Exploit Public-Facing Application (T1190, Initial Access) с прямым выходом на внутреннюю инфраструктуру.

Для пентестера всё это сводится к трём вещам:
  • Авторизация - главная точка отказа, потому что API обслуживает десятки третьих сторон с разными уровнями доступа
  • Бизнес-логика платежей создаёт уникальные вектора (race conditions, double-spending), которые автосканеры не видят
  • Shadow API и устаревшие эндпоинты - норма, потому что миграция идёт быстрее, чем деком

BOLA и BFLA: пентест авторизации финансовых API​

BOLA - подмена идентификаторов объектов​

BOLA (Broken Object Level Authorization, API1:2023 по OWASP API Security Top 10) - уязвимость номер один в финансовых API-аудитах. Суть проста до обидного: API проверяет, что пользователь аутентифицирован, но не проверяет, что запрашиваемый объект принадлежит именно ему.

Контекст применимости: внешний и внутренний пентест, любая архитектура - legacy monolith и modern microservices. В микросервисной архитектуре BOLA встречается чаще, потому что авторизация размазана по нескольким сервисам и каждый реализует её по-своему (а иногда не реализует вовсе).

Kill chain position: Exploit Public-Facing Application (T1190, Initial Access) → доступ к данным других пользователей → Financial Theft (T1657, Impact) при доступе к платёжным функциям.

Методология тестирования:
  1. Создаёте два тестовых аккаунта (User A и User B) - серый ящик обязателен, в чёрном ящике BOLA находится только случайно
  2. Аутентифицируетесь как User A, собираете все запросы к API с идентификаторами объектов
  3. Подставляете идентификаторы объектов User B в запросы User A
Ищите числовые последовательные ID (/accounts/10042, /accounts/10043), UUID из ответов второго аккаунта, композитные идентификаторы в теле POST-запросов.
Код:
curl -s -H "Authorization: Bearer <token_user_a>" \
  "https://api.bank.example/v2/accounts/10043/transactions" \
  | jq '.transactions[0:2]'
Если в ответе транзакции User B - BOLA подтверждена. В Burp Suite Pro расширение Autorize автоматизирует подстановку: настраиваете токен низкопривилегированного пользователя, и каждый запрос дублируется с его credentials. На выходе - таблица: где сервер вернул 200 вместо 403.

Что искать в банковском API конкретно: /accounts/{id}/balance (чужие балансы), /accounts/{id}/transactions (история операций), /users/{id}/kyc-documents (паспорта, адреса), /cards/{id}/details (данные карт). На практике простая подмена transaction ID в запросе к банковскому приложению нередко открывает чужие транзакции, детали счетов и данные карт.

Ограничения: современные API Gateway (Kong, Apigee) с корректно настроенными OPA/Rego-политиками блокируют BOLA на уровне gateway. Но «корректно настроенные» - ключевое слово. В моей практике OPA-политики нередко покрывали процентов 60–70 эндпоинтов, а остальные торчали голые. Это моё наблюдение, не статистика - но оно повторяется из проекта в проект.

BFLA - вызов привилегированных функций через API​

BFLA (Broken Function Level Authorization, API5:2023) - когда обычный пользователь может вызвать административный эндпоинт. В финансовом API это: инициирование возвратов, изменение лимитов транзакций, доступ к batch settlement records.

Контекст применимости: преимущественно внешний пентест, modern API с микросервисной архитектурой. В legacy-монолитах BFLA встречается реже - авторизация обычно централизована.

Kill chain position: Initial Access → Privilege Escalation → Financial Theft (T1657).

Методология: проксируйте весь трафик мобильного/веб-клиента через Burp и соберите все эндпоинты. Затем фаззите пути - если есть /api/v1/user/transactions, проверьте /api/v1/admin/transactions, /api/v1/internal/transactions, /api/v1/management/refunds. Kiterunner с финансовыми wordlist-ами ускоряет процесс: kr scan https://api.bank.example -w routes-large.kite.

В одном проекте я наткнулся на эндпоинт /api/internal/refund - клиентское приложение его не вызывало, но сервер спокойно обрабатывал запросы с обычным пользовательским токеном. POST-запрос с transaction_id и amount выполнял возврат. Никакой дополнительной авторизации. Просто бери и возвращай деньги.

Ограничения: WAF здесь бесполезен - запросы синтаксически корректные. Единственная защита - серверная проверка ролей на каждом эндпоинте. Autorize в Burp выявляет BFLA так же эффективно, как BOLA - вторым проходом с пониженными привилегиями.

Race conditions в платёжных эндпоинтах​

Race condition в платёжном API - два одновременных запроса на перевод проходят до обновления баланса в базе. Результат: double-spending, двойное начисление бонусов или двойное списание с чужого счёта.

Контекст применимости: любой пентест (внешний/внутренний). Наиболее критично для modern-архитектур с микросервисами, где баланс проверяет один сервис, а списание выполняет другой. Legacy-монолиты с синхронными транзакциями менее подвержены, но не иммунны.

Kill chain position: Exploitation → Data Manipulation (T1565, Impact) → Financial Theft (T1657).

В Burp Suite Pro используйте Turbo Intruder или встроенную single-packet attack (доступна с 2023 года): отправка нескольких HTTP/2-запросов в одном TCP-пакете устраняет сетевой jitter и повышает вероятность попадания в race window.

Сценарий: у пользователя 10 000 на счёте. Одновременно отправляете 5 запросов на перевод по 10 000 каждый. Если хотя бы два из пяти проходят - race condition подтверждена. Деньги появились из воздуха.
Python:
# Turbo Intruder (>= 2023.x) - single-packet attack по методу Kettle
# См. PortSwigger Research: 'Smashing the state machine' (2023)
def queueRequests(target, wordlists):
    engine = RequestEngine(endpoint=target.endpoint,
                           concurrentConnections=1,
                           engine=Engine.HTTP2)
    for i in range(5):
        engine.queue(target.req, gate='race1')
    engine.openGate('race1')
    engine.complete(timeout=60)
Проверяйте эндпоинты перевода (/transfer, /payment), применения промокодов (/promo/apply, /cashback/redeem), изменения лимитов.

Ограничения: банки с distributed locks (Redis/ZooKeeper) и сериализуемыми транзакциями (isolation level SERIALIZABLE) устойчивы к race conditions. Но дефолтный isolation level в PostgreSQL - READ COMMITTED, который не защищает от TOCTOU. Проверяйте.

Характерный паттерн атаки: злоумышленники находят устаревший эндпоинт API финтех-компании, не прикрытый современными rate-limiting и fraud-detection контролями. Через него прогоняются списки украденных карт - боты шлют массовые запросы на мелкие транзакции: успешная транзакция подтверждает валидность карты, неуспешная помечается для следующей итерации (card testing / BIN attack). Ущерб - сотни тысяч долларов. Это сочетание Unrestricted Resource Consumption (API4:2023) и Improper Inventory Management (API9:2023): отсутствие rate-limiting на legacy-эндпоинте, который забыли вывести из эксплуатации.

API security тестирование JWT и OAuth в банковских реализациях​

Алгоритмическая подмена​

JWT в финансовых API - стандарт де-факто и стандартный источник головной боли. Распространённая ошибка: сервер принимает алгоритм из заголовка токена без валидации.

Контекст применимости: внешний пентест, modern-архитектуры с JWT-аутентификацией. На legacy с session-based auth неприменимо.

Kill chain position: Unsecured Credentials (T1552, Credential Access) → Valid Accounts (T1078) → Financial Theft.

Algorithm confusion: если сервер ожидает RS256, но принимает HS256, можно подписать токен публичным ключом (часто доступен через JWKS-эндпоинт) как HMAC-секретом. jwt_tool автоматизирует это: python3 jwt_tool.py <token> -X a. Атака none ("alg": "none" с удалённой подписью) в 2025 году встречается редко, но в legacy-интеграциях бывает - я натыкался на такое в платёжном шлюзе, который не обновляли с 2019 года.

kid-параметр и path traversal​

Параметр kid (Key ID) в заголовке JWT указывает серверу, каким ключом проверять подпись. Если значение подставляется в файловый путь без санитизации - path traversal. Пример: "kid": "../../../../../../dev/null" - сервер прочитает /dev/null как пустой ключ, и если он не валидирует длину HMAC-секрета и принимает алгоритм из заголовка токена, HS256-подпись с пустым секретом пройдёт валидацию. В современных библиотеках (PyJWT 2.x+, jose-jwt) такая комбинация условий встречается редко - техника актуальна для legacy-имплементаций или самописных JWT-валидаторов. Тестирование: jwt_tool с флагом -X i, Burp-расширение JWT Editor для редактирования токенов в Repeater.

Ограничения: финансовые API, реализующие FAPI 2.0 (Financial-grade API) с mutual TLS и sender-constrained tokens, практически неуязвимы к JWT-атакам - токен привязан к клиентскому сертификату. Ведущие банки движутся в сторону FAPI + mTLS, но до повсеместного внедрения ещё далеко.

Пошаговая методология тестирования банковских API​

Требования к окружению​

  • ОС: Kali Linux 2024.x+ или любой Linux. macOS - с оговорками (kiterunner требует компиляции из исходников)
  • RAM: минимум 8 ГБ (Burp + браузер + ffuf одновременно), рекомендовано 16 ГБ
  • Инструменты: Burp Suite Pro 2024.x+ с расширениями Autorize, JWT Editor, InQL; ffuf v2.x; kiterunner v2.x (последнее обновление репозитория: проверяйте на GitHub перед использованием); jwt_tool; Postman для реверса проприетарных API-схем
  • Сетевые условия: прямой доступ к целевому API через прокси Burp. Для race condition-тестов - стабильное соединение с минимальным jitter (VPN может мешать таймингу)
  • Модель доступа: минимум два тестовых аккаунта с разными ролями (серый ящик). Чёрный ящик для банковских API неэффективен - без легитимных аккаунтов BOLA/BFLA не протестировать

Recon: инвентаризация и fingerprinting эндпоинтов​

Первый этап - собрать карту API. Что искать:
📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме

Что видит API Gateway и где пентестер проходит незамеченным​

Тестирование банковских API без понимания защитных слоёв - пустая трата времени. Типичный стек: API Gateway (Kong, AWS API Gateway, Apigee) + WAF (Cloudflare, AWS WAF, ModSecurity) + rate limiter + антибот.

Что WAF ловит уверенно:
  • SQL/NoSQL-инъекции в параметрах - сигнатурный анализ цепляет стандартные паттерны (A03:2021 - Injection)
  • Массовый перебор (Brute Force, T1110) - аномальная частота запросов
  • Сканирование директорий с дефолтным User-Agent и скоростью
  • Просроченные и поддельные JWT-токены, манипуляции с iat, exp, aud - если WAF имеет доступ к ключам валидации
Чего WAF не видит:
  • BOLA - запросы синтаксически легитимны, отличается только ID объекта
  • BFLA - вызов существующего эндпоинта с валидным токеном
  • Race conditions - каждый отдельный запрос валиден
  • JWT algorithm confusion - WAF не разбирает логику подписи, если токен структурно корректен
Evasion на практике: замедляйте ffuf до 10–20 req/sec (-rate 15) при фаззинге эндпоинтов. Ротируйте User-Agent. Для обхода rate limiting проверяйте заголовки X-Forwarded-For, X-Real-IP - некоторые API Gateway берут IP клиента из них (API4:2023 - Unrestricted Resource Consumption). Поведенческий анализ, о котором пишут вендоры антибот-решений, действительно эффективен против ботов, но ручной пентест с разумной скоростью и реалистичными паттернами запросов он не ловит.

За два года тестирования финансовых API я пришёл к одному выводу, который подтверждается из проекта в проект: банковская API security - это не про WAF и не про compliance-чеклисты. Это про авторизацию. Только про авторизацию. BOLA остаётся уязвимостью номер один не потому, что её сложно исправить - server-side проверка ownership объекта решается за день. А потому что каждый новый эндпоинт, каждая интеграция с третьей стороной, каждый микросервис - это новая точка, где проверку нужно реализовать заново. И каждый раз кто-то забывает.

PCI DSS не проверяет, может ли User A увидеть баланс User B - это буквально вне скоупа аудита. И именно здесь ломается всё.

Отдельный тренд, который я считаю критическим на ближайшие год-два, - рост атак через устаревшие версии API. Банки мигрируют на v3, а v1 продолжает работать «для обратной совместимости», без fraud-detection, без нового rate-limiting, иногда без корректной авторизации. Кейс Aditya Birla Capital - не экзотика, а стандартная картина 2025 года. С расширением open banking и PSD2-подобных инициатив в России поверхность атаки будет только расти: банки будут вынуждены открывать API, и каждая интеграция - потенциальный BFLA, ожидающий пентестера. Если хочешь разобрать BOLA и race condition на живом API - на HackerLab есть веб-задачи, где авторизацию нужно ломать руками, без подсказок.
 
Последнее редактирование:
Мы в соцсетях:

Взломай свой первый сервер и прокачай скилл — Начни игру на HackerLab

Похожие темы

🚀 Первый раз на Codeby?
Гайд для новичков: что делать в первые 15 минут, ключевые разделы, правила
Начать здесь →
🔴 Свежие CVE, 0-day и инциденты
То, о чём ChatGPT ещё не знает — обсуждаем в реальном времени
Threat Intel →
💼 Вакансии и заказы в ИБ
Pentest, SOC, DevSecOps, bug bounty — работа и проекты от проверенных компаний
Карьера в ИБ →

HackerLab