Чек-лист безопасности API

Sat Aug 22 2026

Чек-лист безопасности API

Действительный JWT подтверждает, кто является вызывающей стороной. Но он не подтверждает, что она может прочитать заказ 12345. Уязвимость, которую я обычно ставлю в приоритет, возникает уже после аутентификации: владение объектом, разрешения на уровне полей, ограничения ресурсов или бизнес-правила никогда не применялись.

Но этот чек-лист лучших практик безопасности API предназначен для производственных проверок в 2026 году. Он прослеживает один запрос от идентификации через разрешение, использование ресурсов, обработку входных данных, транспорт, обнаружение, секреты и проверку. Скопируйте проверки в инженерные задачи или тесты pass/fail.

При этом этот чек-лист лучше всего охватывает авторизацию и обработку запросов. Он не заменяет моделирование угроз для регулируемой платёжной системы или проверку реализации вашего провайдера идентификации.

В этой статье

Издания OWASP API Security Top 10 за 2026 год не существует

А OWASP API Security Project указывает API Security Top 10:2023, выпущенный 5 июня 2023 года, как текущее стабильное издание. Называть его «списком OWASP 2026» было бы неточно: 2026 — это дата проверки, а не номер издания.

Таким образом, таксономия охватывает API1 Broken Object Level Authorization, API3 Broken Object Property Level Authorization, API4 Unrestricted Resource Consumption, API5 Broken Function Level Authorization, API6 Sensitive Business Flows, API7 SSRF, API9 Improper Inventory Management и API10 Unsafe Consumption of APIs. OWASP также охватывает нарушения аутентификации и неправильную конфигурацию безопасности.

OWASP предоставляет таксономию рисков. Моё практическое применение проще: сопоставьте каждому маршруту владельца, предикат авторизации и тест. Руководство Blackhawk по penetration testing REST API охватывает практическое тестирование, которое следует за проверкой дизайна.

[IMAGE PLACEHOLDER: визуальное представление OWASP API Security Top 10 (2023) с чёткой пометкой «текущее стабильное издание по состоянию на 22 августа 2026 года»; источник/ссылка на OWASP API Security Top 10]

Аутентификация зависит от клиента и границы доверия

Начните с разделения функций OAuth, JWT и API keys. OAuth 2.0 — это authorization framework, JWT — формат токена, а API key — учётные данные. API key обычно идентифицирует приложение или интеграцию; сам по себе он не содержит разрешений на уровне объектов.

Клиент или интеграцияПодходящая отправная точкаПроверки, поддающиеся тестированию
Пользователь браузера или мобильного приложенияAuthorization Code with PKCEПроверьте redirect URI, обмен authorization code, PKCE verifier, audience токена и scopes
Машинный клиент в пределах одной границы доверияOAuth 2.0 Client CredentialsПредоставьте каждому клиенту узкие scopes; проверяйте аутентификацию клиента и отзывайте учётные данные при offboarding
Межорганизационная или регулируемая интеграцияmTLS или OAuth with mTLSПроверьте сертификат клиента, цепочку сертификатов, срок действия и привязку сертификата или токена
Планируемая задача или webhook с низкой чувствительностьюAPI keyОграничьте scope ключа, ротируйте и отзывайте его, а также применяйте ограничения для endpoint и tenant
Public client, которому нужны sender-constrained tokensDPoP, если ваш провайдер и библиотеки его поддерживаютПроверьте подпись proof, HTTP-метод, URL запроса, nonce или поведение replay и привязку токена

И используйте поддерживаемую OAuth-библиотеку или identity service. Сравнение Skycloak полезно для выбора между типами клиентов, но окончательное решение по безопасности всё равно принимает ваш API.

OAuth выдаёт клиенту access token; ваш API всё ещё решает, может ли этот токен выполнить эту операцию над этим объектом. Эти решения должен принимать ваш сервер.

Для каждого bearer- или JWT access token проверяйте его подпись по доверенному набору ключей. Проверяйте разрешённый algorithm, issuer, audience, expiry и обязательные claims. Никогда не помещайте client secrets в browser bundles или мобильные приложения. В руководстве по безопасности Node.js и руководстве по безопасности Django рассматривается обработка токенов и middleware для конкретных frameworks.

Валидации JWT по-прежнему нужна стратегия отзыва

Для GET /profile или обычной операции чтения локальная валидация часто практична. Но восстановление аккаунта и авторизация платежа могут требовать вызова introspection, чтобы проверить текущее состояние токена.

МетодПреимуществоСтоимость
Локальная валидация с помощью JWKSБыстрая, способна работать offline и не зависит от вызова authorization server во время запросаОтозванный токен может оставаться пригодным к использованию до истечения срока действия
IntrospectionОтражает текущее состояние токена и быстро обнаруживает отзывДобавляет задержку и зависимость от authorization server

Используйте локальную валидацию, когда окно expiry соответствует вашей модели риска. Рассмотрите introspection для платежей и восстановления аккаунта. Используйте её также при изменении разрешений или в других сценариях, где отзыв критически важен. Уменьшение срока действия снижает воздействие; оно никогда не заменяет авторизацию объекта или контроль отзыва.

Access token на 15 минут и refresh token на семь дней — конкретные отправные точки из вторичных рекомендаций практиков; OWASP их не требует. Я не могу выбрать ваше окно expiry, не зная вашего набора клиентов, потребностей в отзыве и допустимого уровня последствий инцидента.

Зафиксируйте допустимые algorithms, ротируйте signing keys и отклоняйте alg:none, неутверждённые algorithms, неправильный issuer, неправильную audience и просроченные токены. Тестируйте эти отказы напрямую.

Действительный токен не авторизует доступ к объекту

Рассмотрим multi-tenant order API. Этот handler аутентифицирует вызывающую сторону, а затем доверяет идентификатору, предоставленному вызывающей стороной:

app.get("/api/orders/:id", auth, async (req, res) => {
  const order = await db.orders.findById(req.params.id);
  return res.json(order);
});

Более безопасный lookup включает предикат авторизации непосредственно в операцию доступа к данным:

app.get("/api/orders/:id", auth, async (req, res) => {
  const order = await db.orders.findOne({
    id: req.params.id,
    tenantId: req.user.tenantId,
    ownerId: req.user.id
  });

  if (!order) {
    return res.sendStatus(404);
  }

  return res.json(order);
});

Этот пример предполагает, что просматривать заказ может только владелец. Если заказ виден нескольким пользователям в tenant, замените ownerId фактическим предикатом политики: членство в tenant, связь с аккаунтом, роль или другое явно заданное правило.

OWASP API1 формулирует требование прямо: «Проверки авторизации на уровне объектов следует учитывать в каждой функции, которая обращается к источнику данных, используя ID от пользователя». Применяйте эту проверку к чтению, обновлению, удалению, вложенным ресурсам, экспортам и фоновым действиям.

Ответ 404 — распространённый выбор для объектов за пределами видимой области вызывающей стороны, поскольку он не раскрывает существование объекта. Я бы моделировал доступ сотрудников как отдельную явную политику, а не молча убирал условие владения для всех.

BOLA, или Broken Object Level Authorization, — термин OWASP. Команды по-прежнему часто называют уязвимости, связанные с заменой идентификаторов, IDOR. Для предотвращения BOLA и IDOR тестируйте с двумя обычными пользователями, а не с администратором:

  • Заменяйте идентификаторы. Изменяйте числовые ID, UUID, вложенные идентификаторы и идентификаторы tenant.
  • Охватите каждый метод. Тестируйте пути GET, PATCH, DELETE и экспорта.
  • Тестируйте границу. Используйте пользователей из одного tenant и из разных tenant.
  • Проверяйте выводы. Сравнивайте коды состояния, размеры ответов и время выполнения для недоступных объектов.

Пользователь с низкими привилегиями должен безуспешно завершать каждую попытку прочитать, изменить, удалить, экспортировать или определить наличие заказа другого tenant. Используйте руководство по Node.js для деталей реализации в Express; проводите всю процедуру в рамках процесса security testing.

Разрешения на уровне полей блокируют mass assignment

Передача req.body через spread позволяет вызывающей стороне попытаться изменить status, ownerId или paymentState:

await db.orders.update(req.params.id, {
  ...req.body
});

Доступное для записи поле role или isVerified создаёт возможность повышения привилегий. Возврат внутренних полей создаёт чрезмерное раскрытие данных. OWASP API3:2023 объединяет обе прежние проблемы под названием Broken Object Property Level Authorization.

Сначала проверьте body, затем создайте allow-list:

const body = updateOrderSchema.parse(req.body);

const updates = {
  shippingAddress: body.shippingAddress,
  deliveryInstructions: body.deliveryInstructions
};

await db.orders.updateOwned(req.params.id, req.user.id, updates);

В этом примере шаг schema показан для иллюстрации разрешений; для него всё ещё нужны правила типов полей, длины и вложенных значений.

Отделяйте изменения workflow, контролируемые сервером, от обычных обновлений. Клиент может изменить адрес доставки, тогда как только авторизованный workflow может изменить состояние платежа. Возвращайте response DTO, а не объекты базы данных, чтобы audit fields, metadata tenant, платёжные данные и административные флаги оставались внутренними.

Проверки объектов и свойств оставляют третью границу: может ли эта вызывающая сторона вообще вызвать функцию. API5 охватывает это решение на уровне функции, особенно для административных маршрутов. Тестируйте попытки вызвать admin endpoints с токенами обычных пользователей.

Сделайте злоупотребляющие запросы дорогими для отправки и дешёвыми для отклонения

Rate limiting — не декоративная настройка gateway. Для login, password reset, search, export и pagination нужны разные ограничения. Они также нужны дорогим бизнес-операциям. Квоты tenant не менее важны, чем ограничения по IP.

Это отправная политика, готовая для добавления в ticket:

  • Login: пять попыток за 15 минут на IP с контролем на основе identity там, где это уместно.
  • Password reset: более строгие ограничения, чем для обычных чтений, с alert об abuse.
  • Search и export: отдельные ограничения endpoint, ограниченные наборы результатов и квоты на tenant.
  • Pagination: устанавливайте максимальный limit; отклоняйте неограниченные list requests.
  • Business flows: ограничивайте действия, похожие на checkout, по identity, tenant и business state; одних ограничений по IP недостаточно.
  • Failure behavior: возвращайте 429 Too Many Requests и Retry-After; применяйте консервативный fallback, если состояние limiter недоступно.

Пример «пять попыток за 15 минут на IP» взят из практических рекомендаций Quantlab. Это не default OWASP. В общих офисных сетях и мобильных операторах многие пользователи могут находиться за одним адресом, поэтому перед внедрением измерьте количество false positives.

Для order API тестируйте чрезмерно большие значения GET /api/orders?limit=..., повторяющиеся exports, дорогие searches и повторяющиеся запросы, похожие на checkout, пока обычные чтения остаются ниже своего лимита. Ограничения должны ограничивать bandwidth, CPU, memory, storage и business capacity.

Пример ответа; используйте формат, поддерживаемый вашим gateway и клиентами:

HTTP/1.1 429 Too Many Requests
Retry-After: 60
RateLimit-Limit: 60
RateLimit-Remaining: 0

Проверяйте данные на границе и отклоняйте небезопасный ввод

Проверяйте значения path, query, header и body до того, как business logic или persistence начнут их обрабатывать. Строгие schemas, такие как Zod, JSON Schema и Pydantic, должны обеспечивать проверку типов и обязательных полей. Они также должны проверять длины, диапазоны, форматы, перечисляемые значения и допустимую вложенность.

Используйте этот чек-лист границы:

  • Schema: отклоняйте значения за пределами контракта; нормализуйте только там, где контракт определяет нормализацию.
  • Business rules: требуйте положительные, ограниченные количества; shipped order не должен возвращаться в pending.
  • Content: проверяйте Content-Type, размер payload и поддерживаемые encodings.
  • Database: используйте prepared statements и parameterized queries. Руководство Blackhawk по SQL injection охватывает построение queries и тестирование, специфичное для injection.
  • URLs: если API получает удалённый ресурс, разрешайте destinations по allow-list. Блокируйте внутренние диапазоны и диапазоны cloud metadata. Проверяйте каждую destination, к которой HTTP client действительно обратится.
  • Third-party data: разбирайте ответы провайдера по schema, устанавливайте ограничения размера и не допускайте попадания их полей в privileged update paths.

OWASP API7 охватывает SSRF, а API10 — небезопасное использование внешних APIs. Строка, похожая на URL, всё равно является пользовательским вводом.

Внутренним вызовам тоже нужен TLS

Принудительно используйте HTTPS и TLS для public endpoints и вызовов внутренних сервисов. К внутреннему маршруту всё ещё можно получить доступ после ошибки маршрутизации, компрометации workload или неправильной настройки proxy. Требуйте аутентифицированную service identity всякий раз, когда downstream service принимает решения об авторизации.

Проверьте три вещи:

  1. Plaintext HTTP отклоняется или перенаправляется в соответствии с политикой вашего deployment.
  2. Outbound clients проверяют сертификаты и отклоняют недействительные, просроченные или неожиданные identities.
  3. Тесты webhook отклоняют отсутствующие или недействительные signatures, устаревшие timestamps и повторно использованные event IDs, когда провайдер предоставляет replay controls.

Используйте актуальную поддерживаемую платформой конфигурацию безопасного TLS вместо копирования статического списка cipher в чек-лист. Не помещайте bearer tokens в URLs, analytics data и logs.

Логи должны объяснять отказ

Большинство проверок API уделяет слишком много внимания валидации токенов, потому что её легко продемонстрировать. С логированием происходит обратное: создаётся расплывчатая задача «добавить observability», но нет доказательств, что расследователь сможет восстановить картину атаки.

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

{
  "event": "authorization_denied",
  "requestId": "<request identifier>",
  "actor": "<user or service identifier>",
  "tenant": "<tenant identifier>",
  "requestPath": "/api/orders/:id",
  "endpoint": "GET /api/orders/:id",
  "object": "<order reference>",
  "action": "read",
  "policy": "order_owner_or_tenant_member",
  "reason": "object_outside_actor_scope",
  "outcome": "denied",
  "timestamp": "<UTC timestamp>",
  "clientContext": "<redacted network or client context>"
}

Логируйте authentication failures и authorization denials. Логируйте действия высокой ценности, exports, события rate limit и доступ к deprecated или debug endpoints. Никогда не логируйте passwords, access tokens или sensitive payloads.

Настройте alert на повторяющиеся ответы 401 и 403, patterns перебора identifiers, необычные exports и внезапные всплески rate limit. Поддерживайте inventory endpoints и versions. После изменения аутентификации или доступа к данным я бы настоял на новом запуске pentest, а не полагался на старый отчёт.

Секреты — это учётные данные, поэтому при возможной утечке их нужно ротировать

Храните API keys, database passwords, signing keys и service credentials в управляемом secrets store. Ограничивайте каждый secret минимально необходимыми permissions и environment. Никогда не встраивайте secrets в browser bundles или мобильные приложения: клиенты могут их извлечь.

Если credential мог утечь:

  1. Определите каждую систему, которая его использует.
  2. Немедленно отзовите или отключите его.
  3. Выпустите замену с более узким scope.
  4. Удалите его из source, history, build artifacts, logs и error responses.
  5. Проверьте access records на предмет злоупотребления.
  6. Ротируйте связанные credentials, если они подверглись той же утечке.

Утёкший key — это инцидент, даже если у вас нет доказательств его использования. По возможности используйте short-lived tokens, если интеграция их поддерживает, и ротируйте их как по расписанию, так и при подозрении.

Запускайте чек-лист как тесты, а не как документ с политиками

Скопируйте эти строки в release ticket. Каждое условие pass называет evidence, которое может проверить reviewer.

ПроверкаУсловие passEvidence
Inventory endpointsИзвестны каждый host, route, version, debug endpoint и deprecated versionVersioned route inventory с owner и датой вывода из эксплуатации
AuthenticationМеханизм соответствует клиенту; проверяются issuer, audience, expiry, signature, algorithm и claimsMiddleware tests с демонстрацией принятых и отклонённых токенов
Object authorizationИзменения identifiers между пользователями и tenant завершаются отказом для чтений, обновлений, удалений, вложенных ресурсов и exportsTest matrix с пользователями низких привилегий и assertions ответов
Property authorizationДоступные для записи поля находятся в allow-list; sensitive fields нельзя назначить через mass assignmentSchema, DTO и negative tests изменения полей
Function authorizationАдминистративные и обычные функции применяют отдельные policiesRole или policy tests для каждого privileged route
Resource controlsPagination, payloads, queries, exports, business flows и использование tenant ограничены429 tests, quota configuration и tests максимальных значений
ValidationПроверяются schemas, content types, URLs, SQL inputs и ответы third-partyРезультаты boundary tests и review prepared queries
TransportTLS применяется на каждом hop, а webhook signatures проверяютсяPlaintext, certificate, signature, timestamp и replay tests
DetectionSecurity events содержат actor, tenant, route, action, outcome, reason и time без secretsRedacted event samples и alert rules
SecretsCredentials имеют scope, безопасно хранятся, ротируются и могут быть отозваныSecrets inventory, rotation record и repository scan
RetestingИзменения authentication и data access запускают security testing до releaseСвязанный test run или утверждённое исключение

Для order API создайте Alice и Bob в tenant A. Поместите Carol в tenant B. Протестируйте каждую комбинацию order IDs и tenant context. Попробуйте изменить поля и использовать чрезмерно большую pagination. Повторяйте exports и пытайтесь злоупотреблять business flows. OWASP API Security Project также указывает crAPI, намеренно уязвимый API project, для безопасной практики.

Нет теста отказа для cross-tenant — нет release.