Безопасные API: REST, GraphQL, аутентификация и OWASP API Security Top 10
API — невидимая часть веб-приложения, через которую проходит основной трафик данных между сервисами, мобильным клиентом, сторонними партнёрами. В 2026 году API стали основной целью атак: на каждый уязвимый веб-эндпоинт приходится 3–5 уязвимых API. Этот материал — практическое руководство по защите REST и GraphQL API для CISO и тимлидов разработки: разбор OWASP API Security Top 10, выбор аутентификации, rate-limiting, secrets management, специфика GraphQL.
Почему API — отдельный класс угроз
Веб-приложение традиционно атакуется через UI: пользователь заполняет форму, нажимает кнопку. API атакуют напрямую: автоматизированные скрипты вызывают эндпоинты в нужном порядке, обходя любые фронтенд-валидации. Это создаёт три специфики API-безопасности:
- Объём атакуемой поверхности. Один публичный сайт = 30–50 страниц. Тот же сайт через API = 200–500 эндпоинтов. Сложнее покрыть пентестом и сканерами.
- Логика на клиенте. Старые UI-приложения выполняли валидацию на сервере. Современные SPA часто валидируют на клиенте и доверяют запросам — это путь к BOLA, IDOR, BFLA.
- Скрытность. Атаки на API легко маскируются под легитимный трафик мобильного приложения, сложнее выявляются мониторингом, дольше остаются незамеченными.
OWASP API Security Top 10
OWASP API Security Top 10:2023 — обязательный документ для команды разработки. Каждая из 10 категорий — типовая ошибка и способ её закрытия.
API1: Broken Object Level Authorization (BOLA)
Эндпоинт GET /api/orders/12345 возвращает заказ без проверки, принадлежит ли он
текущему пользователю. Простейшая и самая распространённая уязвимость. Решение — проверка владельца
на каждый запрос. Удобный паттерн: ORM-фильтр, который автоматически добавляет WHERE user_id = ?
ко всем выборкам, или middleware, который верифицирует доступ до вызова обработчика.
API2: Broken Authentication
Слабая аутентификация: предсказуемые токены, отсутствие rate-limiting на login, использование «none» в JWT-алгоритме, утечка токенов в URL. Решение — стандартные библиотеки (oauthlib, jose, passport), никогда не реализовывать аутентификацию с нуля, использовать sliding-токены вместо «вечных» сессий, ротация секретов раз в 90 дней.
API3: Broken Object Property Level Authorization (BOPLA)
Эндпоинт возвращает или принимает поля, к которым у пользователя нет прав. Например, PATCH /api/users/me
с телом {"role": "admin"} — а сервер обновляет поле role, потому что не фильтрует входной DTO.
Решение — явные allowlist полей в DTO (Pydantic, class-validator, marshmallow), отдельные модели
для чтения и записи, мнимая иммутабельность критичных полей.
API4: Unrestricted Resource Consumption
Эндпоинт без rate-limiting или с возможностью передать запрос на миллион записей. Атакующий исчерпывает CPU/RAM/БД сервера. Решение — rate-limiting по IP/пользователю/API-ключу, pagination с hard cap (например, не более 100 записей за запрос), таймауты на долгие операции, async-обработка тяжёлых запросов через очередь.
API5: Broken Function Level Authorization (BFLA)
Обычный пользователь может вызвать административный эндпоинт. Часто из-за «обратной авторизации» —
скрытие в UI вместо запрета на бэкенде. Решение — серверная проверка ролей на каждом административном
эндпоинте, использование декораторов @require_role('admin'), отдельные namespace
для административного и публичного API.
API6: Unrestricted Access to Sensitive Business Flows
Чувствительные бизнес-сценарии (бронирование, чекаут, отзывы, регистрация) без анти-автоматизации. Атакующий запускает скрипт, который выкупает все билеты, накручивает рейтинг, регистрирует тысячи фейковых аккаунтов. Решение — bot management, поведенческие лимиты (новый аккаунт не может купить больше N товаров в день), CAPTCHA на критичных переходах, выявление аномалий по device fingerprint.
API7: Server-Side Request Forgery (SSRF)
Бэкенд принимает URL от пользователя и делает к нему запрос. Атакующий передаёт
http://169.254.169.254/latest/meta-data/ (AWS IMDS) и получает токены доступа к инфраструктуре.
Решение — белый список разрешённых доменов, резолюция URL в IP до запроса, блокировка частных диапазонов,
IMDS v2 в AWS (требует токен), отдельный proxy-сервис для исходящих запросов.
API8: Security Misconfiguration
DEBUG=true в production, дефолтные пароли, открытый management-эндпоинт (Spring Actuator, Django admin),
избыточные данные в ответах (полный stack trace), CORS-политика с Access-Control-Allow-Origin: *.
Решение — hardening базовых образов, security audit конфигурации в CI/CD, минимизация раскрытия
(общие сообщения об ошибках, скрытие версий ПО), отдельная инфраструктурная команда с чек-листом.
API9: Improper Inventory Management
Старые версии API, неучтённые тестовые эндпоинты, забытые beta-системы — все остаются доступны через интернет. Решение — обязательная регистрация всех эндпоинтов (OpenAPI/AsyncAPI спецификация как single source of truth), регулярная инвентаризация атакуемой поверхности (например, через GAU, subfinder), процесс «убери лишнее» при выводе из эксплуатации.
API10: Unsafe Consumption of APIs
Ваш сервис доверяет внешнему API больше, чем нужно: использует данные без валидации, следует редиректам без проверки, обрабатывает большие ответы без лимита. Решение — валидация входа независимо от источника, явные таймауты и max body size, отдельный circuit breaker для каждого внешнего API.
Полный текст и регулярные обновления — на owasp.org/API-Security.
Аутентификация API: выбор метода
| Сценарий | Метод | Почему |
|---|---|---|
| Публичный API для сторонних разработчиков | OAuth2 (Authorization Code + PKCE) | Стандарт индустрии, разделение прав через scopes, безопасный обмен токенами |
| SPA + backend (тот же домен) | HttpOnly cookie с session ID + CSRF-токен | Безопаснее JWT в localStorage, защищён от XSS-кражи |
| Мобильный клиент → backend | JWT короткой жизни + refresh-токен в защищённом хранилище | Не нужно слать cookies, токены отзываются через ротацию |
| Service-to-service внутри сети | mTLS или подписанные запросы (HMAC, AWS Signature v4) | Нет «человеческой» аутентификации, нужна криптографическая |
| Простой backend-to-backend, доверенный партнёр | API-key + IP whitelist + rate-limit | Минимум сложности там, где нет публичного риска |
| Машинная аутентификация между сервисами | OAuth2 Client Credentials | Стандартизация и аудит на уровне Identity Provider |
JWT: типичные ошибки
- Алгоритм «none». Никогда не принимайте JWT с алгоритмом «none». Жёстко фиксируйте список разрешённых алгоритмов (обычно RS256 или HS256).
- Слабый секрет. HS256 со словарным секретом — пол-дня для атаки полным перебором.
- Долгоживущий токен. Access-токен на 30 дней — это утечка на 30 дней. Лимит 15–60 минут плюс refresh.
- Отсутствие ревокации. JWT по дизайну неотзываем. Если нужно отзывать (например, при увольнении сотрудника) — добавляйте серверный allowlist токенов или используйте короткий срок жизни + refresh.
Авторизация: RBAC, ABAC, ReBAC
После аутентификации (кто пользователь) нужна авторизация (что ему можно).
- RBAC (Role-Based Access Control). Простая ролевая модель: admin/manager/user. Подходит для большинства приложений с понятной иерархией.
- ABAC (Attribute-Based Access Control). Решение на основе атрибутов: «пользователь может редактировать заказ, если он его автор И статус «черновик» И сегодня будний день». Гибкая, сложная в поддержке.
- ReBAC (Relationship-Based Access Control). Через граф связей: «пользователь имеет доступ к проекту, если состоит в команде, которой принадлежит проект». Популяризирована Zanzibar (Google), удобна для соц-сетей, документных систем.
Для большинства коммерческих SaaS RBAC + 1–2 уровня уточнения (например, ownership-check) даёт нужный баланс. Открытые движки: Casbin, Cerbos, OpenFGA (модель Zanzibar), Oso.
Rate-limiting и quotas на уровне API
Минимальные уровни лимитов:
- На уровне сети (CDN/WAF) — глобальные лимиты по IP, например 1000 запросов/мин.
- На уровне API Gateway — лимиты по API-ключу/токену (например, 100 запросов/секунду, 10 000/час).
- На уровне приложения — endpoint-specific (login 10/мин, password reset 3/час, payment 30/мин).
- Бизнес-quotas — суточные, недельные, месячные (например, free-план: 1000 запросов/день).
Реализация: Redis с sliding-window или leaky bucket. Готовые библиотеки: express-rate-limit, slowapi, django-ratelimit. Для API Gateway — встроенные плагины в Kong, KrakenD, APISIX.
Secrets management
Production-приложение не должно содержать секретов в коде, переменных окружения хост-машины, файлах конфигурации в репозитории. Уровни решений:
- HashiCorp Vault — open-source, ставится локально или в облаке, поддерживает dynamic secrets (БД-учётки на 1 час), отзыв по событию, audit log.
- OpenBao — форк Vault от Linux Foundation после изменения лицензии. Для импортозамещения и отсутствия санкционных рисков — предпочтительнее в РФ.
- Облачные secret managers. Yandex Lockbox, SberCloud Secrets Manager, AWS Secrets Manager — если уже используете соответствующее облако.
- SOPS — для шифрования файлов с секретами в git (когда нужен GitOps-подход).
Базовые правила: автоматическая ротация секретов (раз в 30–90 дней), отдельные секреты для каждого окружения, минимальные права (приложение читает только свои секреты, не всё пространство), audit log каждого обращения, интеграция с CI/CD (не вытаскивать секреты руками).
API Gateway: когда нужен
API Gateway — отдельный слой между клиентом и микросервисами, который принимает все запросы и решает кросс-функциональные задачи.
- Kong — самый популярный open-source Gateway, плагинная архитектура, активное сообщество.
- Apache APISIX — Cloud Native Gateway, оптимизирован под Kubernetes, под лицензией Apache 2.0.
- KrakenD — высокопроизводительный, без хранилища состояния, идеален для агрегации множества backend-сервисов.
- Traefik Enterprise / Tyk — коммерческие альтернативы с расширенной аналитикой.
Gateway оправдан, когда у вас 3+ микросервиса или планируется публичный API с тарифными планами. Для одного монолита с REST-эндпоинтами — избыточная сложность.
GraphQL-специфика
GraphQL даёт клиенту больше выразительности, но и добавляет угрозы:
- Query depth. Лимит вложенности (5–10 уровней). Без него запрос «friends.friends.friends...» уронит БД.
- Query complexity. Анализ стоимости запроса до выполнения. Библиотеки: graphql-cost-analysis, graphql-validation-complexity.
- Batching. Отключайте для критичных операций (login, password reset) — иначе обходится rate-limit одним запросом с 1000 мутаций.
- Introspection. В production отключайте — иначе атакующий видит всю схему.
- N+1. Не безопасность, но проблема производительности. DataLoader — стандартное решение.
Кейс: рефакторинг небезопасного REST API
B2B-сервис документооборота. Команда из 6 разработчиков, монолит на Django + DRF, ~120 эндпоинтов. За год развития накопились типовые проблемы: BOLA в каждом втором эндпоинте, токены без срока жизни, логирование критичных операций отсутствует, секреты в .env прямо на сервере. На pentest — 4 Critical, 11 High.
План рефакторинга на 3 месяца:
- Месяц 1. Внедрение единого middleware с проверкой ownership-уровня (закрывает BOLA по всем эндпоинтам сразу). Ротация всех боевых токенов. Перевод секретов в Vault.
- Месяц 2. Внедрение API Gateway (Kong) с централизованным rate-limiting и логированием. Audit log изменений критичных данных.
- Месяц 3. Threat modeling, переписывание авторизации через Casbin (RBAC + ownership), отключение интроспекции в production, security headers через Gateway.
Re-test через 4 месяца после старта работ: 0 Critical, 2 High (новые, незакрытые сценарии в свежем модуле), 1 Medium. Дополнительный эффект — снижение времени дебага продакшен-инцидентов с дней до часов благодаря централизованному audit log.
Сравнение решений: API Gateway, secrets manager, API monitoring
Зрелая защита API строится из трёх ортогональных классов решений: Gateway (контроль входящего трафика), secrets manager (управление ключами и токенами), API monitoring (детект аномалий).
| Класс | Решения | Когда выбирать |
|---|---|---|
| API Gateway | Kong, Apache APISIX, KrakenD, Tyk, Traefik Enterprise | Kong — стандарт, плагинная архитектура; APISIX — для Kubernetes-native; KrakenD — для агрегации многих backend-ов; Tyk — коммерческая аналитика |
| Secrets manager | HashiCorp Vault, OpenBao, Yandex Lockbox, AWS Secrets Manager, Doppler | Vault — on-prem стандарт; OpenBao — open-source-форк под импортозамещение; Lockbox — для проектов на Yandex Cloud; Doppler — managed cloud для небольших команд |
| API security monitoring | Wallarm API Security, Salt Security (зарубежный), Noname Security, custom WAF+SIEM | Wallarm — единый российский стек, оптимально для среднего бизнеса; custom — для команд с зрелой ИБ-практикой |
| OAuth2 / OIDC сервер | Keycloak, Ory Hydra, Authentik, Auth0 (зарубежный) | Keycloak — стандарт; Ory Hydra — для headless-сценариев; Authentik — современный UX, активная разработка |
Расширенный кейс: API-first SaaS с массовым BOLA
B2B-SaaS аналитики «Заказчик Г» — платформа для маркетинговых агентств, ~140 клиентских кабинетов, ~2300 пользователей суммарно. Архитектура: Python+FastAPI, PostgreSQL, REST API (~180 эндпоинтов), React SPA. На pentest (формат grey-box, 4 недели) обнаружили массовый BOLA: 73 из 180 эндпоинтов позволяли менять project_id в URL и получать данные чужих клиентов. Эта одна цепочка эксплуатации давала полный доступ к 1.4 млн отчётов всех клиентов.
План восстановления (10 недель):
- Week 1. Экстренное rate-limit на критичные эндпоинты (50 req/мин/учётка), мониторинг через ELK + правила корреляции для детекта аномальных паттернов сканирования.
- Weeks 2–4. Внедрение единого ownership-middleware: при каждом запросе с project_id в URL автоматическая проверка «принадлежит ли этот project текущему workspace пользователя». Закрыло BOLA по всем 73 эндпоинтам сразу.
- Weeks 5–6. Перевод секретов из .env в HashiCorp Vault, ротация всех боевых ключей (БД, S3, SMTP, токены интеграций), audit log обращений к Vault.
- Weeks 7–8. Внедрение Kong как API Gateway, централизованный rate-limit, логирование в Wazuh, OAuth2 для публичного API партнёрам.
- Weeks 9–10. Threat modeling нового модуля «общие папки», переписывание авторизации через Casbin (RBAC + ABAC + ownership), интеграция SAST (Semgrep) и SCA (Snyk) в CI.
Re-test через 12 недель: 0 Critical, 1 High (новый эндпоинт массовой выгрузки требовал отдельной rate-limit логики), 3 Medium. Стоимость проекта — 4.8 млн ₽ + 80 тыс. ₽/мес постоянных расходов на Vault + Kong + monitoring. Сравнительная стоимость потенциальной утечки 1.4 млн отчётов — ~50 млн ₽ штрафа РКН + полная потеря enterprise-клиентов.
Стандарты и регуляторы
- OWASP API Security Top 10 (2023) — основной справочник по угрозам API.
- OWASP ASVS — стандарт верификации, секции по API.
- RFC 6749 (OAuth 2.0) — спецификация OAuth 2.
- RFC 7519 (JWT) — спецификация JSON Web Token.
- OpenID Connect Core 1.0 — поверх OAuth 2.
- cve.org — реестр CVE.
- fstec.ru — требования к защите API в КИИ.
Связанные материалы
- Защита веб-приложений: WAF, DDoS, security headers — внешний контур над API.
- Secure SDLC: SAST/DAST/SCA для регулярной проверки API-кода в CI/CD.
- Тестирование на проникновение: ручной поиск BOLA, BFLA, SSRF в реальном приложении.
- Защита персональных данных: правовые требования к API, передающим ПДн.
FAQ о безопасности API
JWT, OAuth2, API-ключ, mTLS — что выбрать для авторизации API?
Зависит от модели: публичный API для сторонних разработчиков — OAuth2 с access/refresh-токенами. Внутренние сервисные вызовы (service-to-service) — mTLS или подписанные запросы (HMAC). API мобильного клиента вашего же приложения — JWT с коротким сроком жизни + refresh-токен в HttpOnly cookie. Простой backend-to-backend без публичного выхода — API-ключ с rate-limit и whitelist IP. Главное правило: один механизм, реализованный правильно, лучше трёх «полу-правильно».
Что такое BOLA и почему это самая опасная уязвимость API?
BOLA (Broken Object Level Authorization) — №1 в OWASP API Security Top 10. Атакующий меняет ID объекта в URL (например, GET /api/invoices/12345 → 12346) и получает чужие данные, потому что бэкенд проверяет только аутентификацию (пользователь залогинен), но не авторизацию (имеет ли он право на этот объект). Эта уязвимость встречается на 70-80% pentest и часто даёт массовый доступ к данным всех пользователей. Решение — обязательная проверка владельца объекта в каждом обработчике запроса, желательно через единый middleware или ORM-фильтры.
Как защитить API от SSRF, когда сервер должен делать внешние запросы (webhook-и, импорт по URL)?
Базовый подход: белый список доменов, на которые разрешены исходящие запросы. Если белый список невозможен (например, webhook-и партнёров) — резолвить URL в IP до запроса и блокировать частные диапазоны (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.169.254 — AWS IMDS, ::1). Использовать отдельный сервис-прокси с минимальными правами, через который проходят все внешние вызовы. Включить IMDS v2 в AWS (требует токен в запросе). Логировать все исходящие запросы для расследования инцидентов.
Где хранить секреты для production: переменные окружения, файлы, Vault?
Переменные окружения — минимальный уровень, проще чем хранить пароли в коде, но всё ещё попадает в логи процессов, дампы памяти, кор-файлы. Файлы (.env) — не лучше переменных и опасны при случайных git-коммитах. Production-уровень — централизованный secrets manager: HashiCorp Vault (open-source, ставится локально), OpenBao (форк Vault от LF, для импортозамещения), AWS Secrets Manager / Yandex Lockbox / SberCloud Secrets Manager. Базовые принципы: автоматическая ротация (раз в 30-90 дней), audit log каждого обращения, минимальные права (приложение читает только свои секреты), отдельные секреты для каждого окружения.
Нужен ли отдельный API Gateway или можно обойтись nginx и кодом?
Для нескольких сервисов с похожими требованиями (аутентификация, rate-limiting, логирование, CORS) API Gateway сильно упрощает жизнь — Kong, KrakenD, Apache APISIX. Он берёт на себя кросс-функциональные задачи, освобождая код приложения. Если у вас один монолит — добавлять Gateway избыточно, достаточно настроить nginx и middleware. Если 5+ сервисов / микросервисов — Gateway уже окупается. Если планируете публичный API для партнёров с тарифными планами и квотами — Gateway почти обязателен.
Чем GraphQL опаснее REST с точки зрения безопасности?
GraphQL даёт клиенту больше контроля над запросом: можно вложенно запрашивать связанные объекты, что создаёт три новых класса угроз. Первый — query depth attack: вложенность поля «друзья друзей друзей» взрывает БД. Решение — depth limit (5-10 уровней). Второй — query complexity attack: запрос, который при разворачивании создаёт миллионы операций. Решение — cost analysis, лимит на сложность. Третий — batching attack: множество вложенных мутаций в одном запросе, обходящих rate-limit. Решение — отключать batching для критичных операций (login, password reset, payment). Плюс отдельная угроза — введение в production включенного introspection (показывает всю схему злоумышленнику). В production introspection отключают.
Какие минимальные требования к логированию API?
Каждый запрос: timestamp, user_id (если есть), API-ключ или клиентский ID, метод, путь, IP, User-Agent, статус ответа, длительность. Тело запроса — не логируйте полностью, маскируйте чувствительные поля (пароли, токены, номера карт, серии паспортов). Изменения данных — отдельный audit-log с before/after. Аутентификация — успешные и неудачные попытки. Административные действия — отдельным потоком с долгим хранением. Минимальное retention для compliance — 6 месяцев, для 152-ФЗ практичнее год. Защита логов от модификации — обязательна (write-once хранилище или SIEM с контролем целостности).
Что хуже — IDOR или BOLA, или это одно и то же?
BOLA (Broken Object Level Authorization) — это формальное название из OWASP API Security Top 10 для уязвимости, которую раньше называли IDOR (Insecure Direct Object Reference). По сути — то же самое: атакующий меняет идентификатор объекта в запросе и получает чужие данные. Разница в нюансе: IDOR — общий термин для веб-приложений и API, BOLA — точное название для API. В отчётах pentest 2024+ корректнее использовать BOLA. Опаснее, чем XSS или SQLi, потому что эксплуатируется в одну строку, без подготовки payload-а — атакующему достаточно сменить число в URL.
Нужно ли подписывать webhook-и партнёрам? Как?
Обязательно подписывать каждый исходящий webhook — иначе подделать запрос от вашего имени тривиально. Стандарт: HMAC-SHA256 от тела запроса + timestamp + nonce, в заголовке X-Signature. Партнёр на своей стороне проверяет подпись и отклоняет timestamp старше 5 минут (защита от replay-атак). Дополнительно: rotation секретов раз в 90 дней, отдельный секрет для каждого партнёра, отдельный секрет для каждого окружения. Эталонные реализации — у Stripe (Stripe-Signature) и GitHub (X-Hub-Signature-256), их документация — хороший шаблон.
Как защититься от reverse engineering мобильного API?
Полностью невозможно — любой клиент, исполняемый на устройстве пользователя, можно разобрать. Реалистичная цель — повысить стоимость reverse engineering: certificate pinning (приложение принимает только конкретный сертификат сервера), obfuscation бинарного кода (R8/ProGuard для Android, Hermes для React Native), детект Frida/Magisk/jailbreak с soft-block, перенос критичной логики на сервер (расчёт цены — на бэкенде, не на клиенте), временные токены с коротким TTL, anti-replay механизмы. Главное правило: не доверять клиенту — все важные проверки делать на бэкенде, даже если они есть в коде клиента.
Обсудить аудит API Бесплатная 30-минутная встреча: текущее состояние API, риски, ориентировочный объём работ.