API уязвим не из-за одного забытого заголовка, а когда у него с самого начала слабый security contract.
Глава собирает защиту API из нескольких слоев: identity и authorization checks, rate limiting, schema validation, anti-replay, abuse prevention и secure lifecycle самого интерфейса.
В архитектурных обсуждениях через нее удобно разбирать public edge, internal APIs, trust zones и то, почему безопасность интерфейса начинается еще до первой ручки в OpenAPI.
Практическая польза главы
Практика проектирования
Используйте материал по паттернах защиты API, контрактах безопасности и abuse mitigation, чтобы формировать архитектурные security-требования до этапа реализации.
Качество решений
Проверяйте решения через модель угроз, security invariants и управляемость контролей в production, а не только через чеклист соответствия.
Аргументация на интервью
Стройте ответ в формате threat -> control -> residual risk, показывая связь между бизнес-сценарием и техническими мерами защиты.
Формулировка компромиссов
Явно описывайте компромиссы по паттернах защиты API, контрактах безопасности и abuse mitigation: UX friction, накладная задержка (latency overhead), стоимость сопровождения и требования compliance.
Контекст
OWASP Top 10 в контексте System Design
Безопасность API — это конкретизация рисков OWASP под конкретную поверхность программного интерфейса вашей системы.
Программный интерфейс (API) — самая открытая поверхность системы: его адрес известен, документация публична, а за ней лежат чужие данные и деньги. API Security Patterns — это набор решений, который держит интерфейс рабочим под нагрузкой, в среде и при активном противнике. Цельной «безопасности» не бывает — она собирается из протоколов аутентификации, политики доступа, защиты от злоупотреблений (abuse) и наблюдаемости, и каждый слой стоит денег и латентности.
Базовые паттерны защиты API
Строгая аутентификация и краткоживущие токены
/, взаимная -аутентификация между сервисами, ротация токенов и понятная стратегия отзыва.
Точная авторизация
Аутентификация говорит «кто», но защищает «что можно»: ролевые и атрибутные правила, права в рамках арендатора, движок политик и запрет по умолчанию — на шлюзе и в каждом сервисе.
Проверка входных данных и схемы
Всё, что пришло снаружи, — недоверенный ввод: строгая проверка по JSON-схеме и контракту OpenAPI, нормализация и отклонение неизвестных полей, чтобы лишний атрибут не дотянулся до модели.
Ограничение частоты и защита от злоупотреблений
Квоты на пользователя, приложение и арендатора держат стоимость и доступность под контролем; добавьте сдерживание всплесков, обнаружение ботов и адаптивное ограничение трафика.
Защита от повторного воспроизведения и подпись запроса
, отметка времени и HMAC/подпись, политика допустимого расхождения часов и окно действия запроса.
Сетевая модель нулевого доверия
Внутренняя сеть — не периметр доверия: ни один внутренний программный интерфейс (API) не считается своим по умолчанию, отсюда взаимная аутентификация и сегментация сети.
Типовые сценарии атак
BOLA/IDOR на object-level API
Риск: Пользователь получает доступ к чужим объектам при корректной аутентификации, но слабой авторизации.
Митигация: Проверки политики на уровне объектов, , запрет по умолчанию и обязательная проверка владельца объекта.
Token replay
Риск: Перехваченный токен используется повторно и позволяет выполнять привилегированные действия.
Митигация: Краткоживущие токены, с отметкой времени, sender-constrained токены и .
Массовое назначение полей (mass assignment) и злоупотребление схемой
Риск: Запрос несёт лишние поля, и без явного фильтра они дописываются в модель — атакующий меняет атрибут, который менять не должен.
Митигация: Схема со строгим разрешённым списком полей, отклонение неизвестных полей и серверная проверка того, какие поля вообще принадлежат этому клиенту.
Массовый сбор данных через API и злоупотребление бизнес-логикой
Риск: Атака не ломает аутентификацию — она пользуется легитимными эндпоинтами для массового сбора данных или фрода, и обычные проверки доступа её не замечают.
Митигация: Адаптивные лимиты запросов, поведенческие сигналы, квоты на арендатора и многослойная защита от ботов.
Spec
OAuth 2.0 DPoP (RFC 9449)
Спецификация proof-of-possession на уровне приложения: структура proof-токена JWT, jkt-привязка и серверные одноразовые значения.
Sender-constrained токены: DPoP и mTLS-bound
работает по принципу «кто принёс, тот и владелец»: перехваченный токен полностью рабочий. Sender-constrained токен криптографически привязан к ключу клиента — кража токена без кражи ключа бесполезна. Два стандартных способа привязки разобраны ниже.
DPoP — proof-of-possession на уровне приложения
RFC 9449Как работает
- Клиент генерирует пару ключей: остаётся у него (в браузере — non-extractable ключ WebCrypto), уходит серверу.
- На каждый запрос клиент создаёт DPoP proof — компактный с заголовком
typ: "dpop+jwt"и публичным ключом вjwk, подписанный приватным ключом. - Внутри proof:
jti(уникальный идентификатор для replay-детекции),htm(-метод),htu(URI без query и фрагмента),iat; при вызове API — ещёath, SHA-256-хэш . - Сервер авторизации кладёт в токен подтверждение
cnf.jkt— base64url JWK SHA-256 thumbprint публичного ключа. Токен передаётся какAuthorization: DPoP <token>, а не Bearer. - Resource server проверяет подпись proof, совпадение
htm/htuс фактическим запросом, свежестьiat/jtiи равенствоjktключу из proof. - Против заранее заготовленных proof сервер выдаёт в заголовке
DPoP-Nonceи отвечает ошибкойuse_dpop_nonce; клиент повторяет запрос, включив его в proof.
Против чего: Украденный без приватного ключа бесполезен; привязка htm/htu не даёт переиграть запрос на другой эндпоинт; серверный ломает proof, заготовленные при XSS-краже.
Цена: Подпись на каждый запрос (CPU и латентность), серверное хранилище jti для replay-детекции, дополнительный цикл ретраев на серверном (use_dpop_nonce) и заметно более сложные клиентские SDK.
mTLS-bound токены — привязка через взаимную аутентификацию канала
RFC 8705Как работает
- Клиент устанавливает -соединение (взаимный ) с сервером авторизации и предъявляет : PKI-метод
tls_client_auth(сертификат от доверенного ) илиself_signed_tls_client_auth(ключ зарегистрирован черезjwks). - Сервер кладёт в выданный токен подтверждение
cnfс членомx5t#S256— base64url SHA-256-хэш DER-кодировки клиентского сертификата. - Каждый вызов API тоже идёт по : resource server берёт сертификат из -слоя и сравнивает его хэш со значением
x5t#S256в токене. - Хэши не совпали — запрос отклоняется с 401 и кодом
invalid_token: токен предъявил не тот клиент, которому он был выдан.
Против чего: Тот же proof-of-possession, что у DPoP, но без подписи на каждый запрос: канал сам доказывает владение ключом. Бонус — одновременно закрывает и аутентификацию клиента перед эндпоинтом выдачи токенов.
Цена: до edge — боль при и на балансировщике (сертификат нужно пробрасывать до приложения), плюс PKI и ; для браузерных практически недоступен.
| Механизм | Где уместен | Почему |
|---|---|---|
| DPoP | Публичные клиенты: (SPA), мобильные приложения, CLI — везде, где клиентский сертификат недоступен. | Работает на уровне приложения, проходит через любые и прокси без проброса сертификата. |
| mTLS-bound | B2B-интеграции, межсервисные вызовы, финансовые API с управляемыми клиентами. | Нет криптографии на каждый запрос; естественно ложится на сервисную сетку и существующую PKI. |
| Оба валидны | FAPI 2.0 Security Profile требует sender-constrained токены и допускает оба механизма. | Чистый Bearer для high-stakes API в финансовом профиле уже не считается достаточным. |
Подписи запросов: HMAC и HTTP Message Signatures
Токен подтверждает, кто вызывает API; запроса — что именно он отправил: метод, путь, заголовки и тело не были изменены по дороге. Образец HMAC-схемы — AWS Signature Version 4.
HMAC-подпись по образцу AWS SigV4
- Канонизация. Запрос приводится к единственно возможной форме: метод, URI-encoded путь, отсортированный query string, канонические заголовки (lowercase, отсортированы, без лишних пробелов), список подписанных заголовков и SHA-256-хэш тела. Любая неоднозначность здесь — будущий «signature mismatch».
- String to sign. Из канонического запроса собирается строка: алгоритм
AWS4-HMAC-SHA256, timestamp ISO 8601, область действия ключаYYYYMMDD/region/service/aws4_requestи хэш канонического запроса. - Производный ключ. Секрет не подписывает напрямую: цепочка HMAC-SHA256 («AWS4»+секрет → дата → регион → сервис →
aws4_request) даёт ключ, ограниченный днём и сервисом, — утечка подписи не раскрывает долгоживущий секрет. - Заголовок. В заголовок авторизации
Authorizationуходят алгоритм,Credential(ключ + область действия),SignedHeadersиSignature. Сервер повторяет все шаги и сравнивает результат; расхождение часов больше 15 минут — отказRequestTimeTooSkewed.
Против чего: подделка и несанкционированное изменение запроса (tampering); timestamp в подписи ограничивает окно повторного воспроизведения; производный ключ снижает урон от утечки.
Цена: хрупкая — прокси переписывают заголовки и нормализуют URL, отладка «signature mismatch» мучительна, а общий секрет нужно защищать на обеих сторонах.
HTTP Message Signatures (RFC 9421) — стандартизация
- Два заголовка:
Signature-Inputперечисляет покрытые компоненты и параметры подписи,Signatureнесёт само значение. - Подписываются явно выбранные компоненты: derived-компоненты
@method,@target-uri,@authority,@path,@query,@status— плюс любые -заголовки по имени. - Параметры подписи —
created,expires,keyid,alg,nonce,tag: окно против повторов и идентификация ключа встроены в стандарт. - Алгоритмы: RSASSA-PSS, ECDSA P-256/P-384, EdDSA (Ed25519) и HMAC-SHA256 — асимметричная подпись снимает проблему общего секрета на двух сторонах.
- Зачем стандарт: вместо зоопарка самодельных схем (клоны SigV4, draft-cavage) — подпись, которая переживает доброкачественные трансформации прокси, потому что покрывает только явно выбранные компоненты.
Защита от повторного воспроизведения и идемпотентность
перехваченного запроса — атака; повтор запроса клиентом после таймаута — норма. Два механизма ниже различают эти случаи и работают в паре.
Окно timestamp + nonce
- Клиент кладёт в подписанную часть запроса timestamp и уникальный одноразовый .
- Сервер отклоняет запросы вне допустимого окна (типично минуты, с поправкой на ); у AWS SigV4 это 15 минут.
- Внутри окна сервер запоминает увиденные (кеш с , равным окну) и отклоняет повторы. Окно ограничивает размер хранилища: вечно хранить nonce не нужно.
- В кластере -хранилище обязано быть общим для всех реплик — иначе атакующий повторит запрос через соседнюю реплику, которая этот nonce ещё не видела.
Цена: общее -хранилище на пути каждого запроса, ложные отказы при рассинхронизации часов, а ширина окна — компромисс между размером хранилища и допуском для медленных клиентов.
Ключи идемпотентности (idempotency keys) — смежный механизм
- Клиент генерирует (обычно UUID) на бизнес-операцию и передаёт его в заголовке
Idempotency-Key, который стандартизирует черновик IETF httpapi. - Сервер атомарно («проверь-и-запиши» одной операцией) сохраняет ключ и результат первого выполнения — код и тело ответа, включая ошибки. Повтор с тем же ключом возвращает сохранённый результат, не выполняя операцию заново.
- Ключи живут ограниченно: Stripe, чья реализация стала образцом для черновика IETF, удаляет ключи старше 24 часов.
- Разница с : она отклоняет повтор — это атака; ключ идемпотентности возвращает тот же результат — это легитимный . В write-API нужны оба механизма одновременно.
Ограничение частоты запросов и квоты на API-шлюзе
От обычно ждут защиты от отказа в обслуживании (), но тот же контроль удерживает счёт за инфраструктуру, изолирует арендаторов друг от друга и сдерживает массовый сбор данных. Базовый алгоритм на шлюзах — «ведро токенов» (token bucket).
Механизм
- Token bucket: на каждый ключ лимита заводится «ведро» ёмкостью B токенов, пополняемое со скоростью R в секунду. Запрос забирает токен; пустое ведро — ответ 429 с
Retry-Afterдля повторной попытки. B задаёт допустимый burst, R — устойчивую скорость. - Ключ лимита — аутентифицированный principal: API-ключ,
client_id, пользователь, тенант. На лимиты складываются в иерархию: per-user внутри per-tenant внутри глобального. - Rate limit и — разные контроли: лимит защищает систему от всплесков на горизонте секунд, квота — бизнес-контракт на период (сутки, месяц, тариф). Шлюз должен считать оба.
- На распределённом шлюзе счётчики либо в общем сторе (Redis — точно, но дороже по латентности), либо локальные с фоновой синхронизацией (быстро, но допускает кратковременный перебор лимита).
Частые ошибки
- Лимит по IP: за /CGNAT мобильного оператора один адрес — тысячи легитимных пользователей, а атакующий ротирует IP. Ключом должен быть principal; IP — только для неаутентифицированного трафика.
- Лимитировать только после аутентификации: сама проверка аутентификации (хэширование, поход к ) — дорогая операция, которую нужно прикрыть дешёвым лимитом до неё.
- 429 без
Retry-Afterи без джиттера на клиенте — повторные попытки приходят синхронной волной, и лимит сам порождает . - Один глобальный лимит без : шумный сосед выедает общий бюджет, и страдают все остальные.
Секреты клиентов: client_secret против private_key_jwt
Машинные клиенты (client credentials, серверные интеграции) должны как-то аутентифицироваться перед эндпоинтом выдачи токенов. Выбор механизма определяет, что именно утечёт при компрометации и насколько больно ротировать.
client_secret — общий секрет
- — симметричный : он передаётся на эндпоинт выдачи токенов при каждом обращении и должен храниться на обеих сторонах.
- Слабости: утечка на любой из сторон равна компрометации; секрет просачивается в логи, конфиги и CI; массовая ротация требует координации с каждым клиентом.
private_key_jwt — client assertion (RFC 7523)
- Клиент держит ; сервер авторизации знает только публичный — зарегистрированный напрямую или опубликованный через
jwks_uri. - На эндпоинт выдачи токенов клиент отправляет параметр
client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearerиclient_assertion— , подписанный приватным ключом (документ RFC 7523; в OpenID Connect метод называетсяprivate_key_jwt). - В assertion:
issиsubравныclient_id,audуказывает на сервер авторизации, короткийexpиjtiпротив повторного использования. - Сервер проверяет подпись по зарегистрированному ключу. Секрет не передаётся по сети вовсе, а компрометация базы сервера не раскрывает ключ клиента — там только публичные части.
Ротация
- Ротация секрета — всегда окно двух значений: регистрируем новый секрет, перекатываем клиентов, отзываем старый. Без поддержки двух активных секретов ротация превращается в простой.
jwks_uriделает почти бесплатной: клиент публикует новый ключ рядом со старым, сервер подхватывает его сам — координация не нужна.- Любому секрету — срок жизни и алерт на приближение истечения: «вечный» client_secret в проде равен по профилю риска.
Secure API lifecycle
Без замкнутого цикла безопасности защита программного интерфейса быстро рассыпается на точечные правки после каждого инцидента. Ниже — рабочий цикл, где каждый этап готовит входы для следующего и возвращает обратную связь назад в проектирование.
Текущий этап
1. Проектирование
Определяем границы доверия, abuse-сценарии и security-требования до написания кода: кто вызывает API, какие данные передаются, где возможна эскалация привилегий.
- • STRIDE/LINDDUN по группам endpoint'ов и бизнес-флоу
- • Явная модель AuthN/AuthZ, tenant isolation и классификация данных
- • Security acceptance criteria в OpenAPI/ADR
Следующий этап
2. Разработка
Встраиваем проверки в pipeline: код, зависимости и секреты автоматически проверяются до merge и продвижения build-артефакта.
- • SAST + secret scanning + dependency/SBOM scan
- • Lint/OpenAPI checks: auth scopes, schema strictness, rate-limit hints
- • Стандартные middleware/библиотеки для auth, validation и signature checks
Матрица контролей безопасности API
| Зона | Контроли | Как валидировать | Действие при провале |
|---|---|---|---|
| Identity and Access | OAuth2/OIDC, mTLS, JWT claim checks, RBAC/ABAC. | AuthN/AuthZ test suites, forbidden-path integration tests. | Block request, log policy decision, alert security owner. |
| Input and Schema | OpenAPI contract validation, canonicalization, strict parsing. | Negative tests, fuzzing, schema drift checks in CI. | Reject payload with explicit error code, track abuse signal. |
| Abuse and Availability | Rate limits, WAF rules, idempotency keys, replay protection. | Load/adversarial tests, bot simulation, replay scenario drills. | Throttle/block source, auto-escalate if pattern persists. |
| Sensitive Data | Field-level masking, minimization, encryption in transit and at rest. | Log inspection checks, DLP scans, PII-safe response snapshots. | Mask output, quarantine endpoint, open compliance incident. |
| Observability and Response | Audit logs, security metrics, trace correlation with tenant context. | Incident playbook drills, detection rule validation, MTTR reviews. | Activate containment playbook and temporary hardening policies. |
Data
Data Governance & Compliance
Без политик работы с данными именно программный интерфейс становится главным каналом утечки персональных данных (PII) — он отдаёт ровно то, что вернул в ответе.
Sensitive data rules for APIs
Чувствительные поля не отдаются по умолчанию — только то, что попало в явный разрешённый список полей; забыли поле в списке — клиент его не увидит, а это безопаснее обратного промаха.
Персональные данные (PII) в логах и трассировке маскируются или вовсе не пишутся: лог живёт дольше запроса и попадает в больше рук.
Версионирование программного интерфейса не должно ослаблять гарантии безопасности старых клиентов — иначе апгрейд превращается в скрытую регрессию защиты.
Публичный и внутренний интерфейсы — это разные уровни доверия: у них разные базовые требования к безопасности и разные ключи доступа.
Текст ошибки не должен выдавать внутреннее устройство — имена сервисов, структуру базы данных и правила политик доступа: это бесплатная разведка для атакующего.
Операционные метрики
Unauthorized request block rate
Target: 100%
Показывает, что запрет по умолчанию работает для неавторизованных и невалидных запросов.
P95 security validation latency
Target: < 30 ms
Контроли безопасности живут на горячем пути запроса — они не должны заметно бить по отклику для пользователя и целям уровня обслуживания () программного интерфейса.
Critical API vuln remediation time
Target: < 24 hours
Оценивает скорость устранения найденных рисков в публичной поверхности.
Replay/abuse incident MTTR
Target: < 60 minutes
Чем быстрее локализован сценарий злоупотребления, тем меньше финансовый и репутационный ущерб.
Roadmap внедрения
Фаза 1 (0-30 дней)
Фокус: Инвентаризация поверхности API
Результат: Каталог API, классификация критичности, для каждого публичного контракта.
Фаза 2 (30-60 дней)
Фокус: Базовые обязательные контроли
Результат: Единые политики аутентификации и авторизации (AuthN/AuthZ), и на шлюзе и границе сети.
Фаза 3 (60-90 дней)
Фокус: Устойчивость к злоупотреблениям
Результат: , защита от ботов, корреляция телеметрии и автоматизация потоков обнаружения.
Фаза 4 (90+ дней)
Фокус: Операционная зрелость
Результат: Регулярные по сценариям атак, разбор метрик и постоянный бэклог укрепления защиты.
Типичные антипаттерны
Полагаться на защиту периметра и не проверять права доступа внутри сервиса: один пробитый периметр — и весь внутренний трафик считается доверенным.
Смешивать пользовательские и машинные токены без явной модели привилегий — машинный токен с правами человека обходит половину контролей.
Разрешать повторные попытки (retry) в пишущих эндпоинтах без защиты от повторного воспроизведения и ключей идемпотентности: один ретрай — и платёж проходит дважды.
Логировать тело запроса целиком в проде — лог становится самой длинной утечкой чувствительных данных.
Отключать строгую проверку схемы ради «быстрого релиза»: дыру в валидации находят раньше, чем успевают вернуть проверку.
References
- OWASP API Security Top 10
- Best Current Practice for OAuth 2.0 Security (RFC 9700)
- OAuth 2.0 Demonstrating Proof of Possession — DPoP (RFC 9449)
- OAuth 2.0 Mutual-TLS Client Authentication and Certificate-Bound Access Tokens (RFC 8705)
- HTTP Message Signatures (RFC 9421)
- JWT Profile for OAuth 2.0 Client Authentication and Authorization Grants (RFC 7523)
- AWS Signature Version 4: создание подписанного запроса
- FAPI 2.0 Security Profile (OpenID Foundation)
- The Idempotency-Key HTTP Header Field (IETF draft, httpapi WG)
- Stripe API: idempotent requests
- NIST API Security Guidance
Связанные главы
- OWASP Top 10 в контексте System Design - Даёт карту классов уязвимостей; на поверхности программного интерфейса они оборачиваются конкретными атаками — BOLA, массовым назначением полей (mass assignment) и обходом аутентификации.
- Идентификация, аутентификация и авторизация - Закладывает контур управления доступом (IAM); пока его нет, контроли безопасности API держатся на полумерах и легко обходятся.
- Zero Trust: архитектура нулевого доверия - Поднимает те же принципы на уровень архитектуры: проверять каждый запрос и решать о доступе по контексту, а не по факту нахождения внутри сети.
- Secrets Management Patterns - Покрывает безопасное управление API-ключами, и токенами в среде выполнения и CI/CD.
- Data Governance & Compliance - Связана с политиками обработки и требованиями аудита для API, работающих с чувствительными данными.
