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

Статья описывает порядок для небольшой команды, у которой API уже работает. Подробный разбор по слоям с ролями, способами входа и ценами лежит на странице «Защита API от несанкционированного доступа», здесь же только последовательность и ловушки.

Коротко. Сначала список методов и потребителей, затем вход, затем права на каждый объект, затем лимиты. Чаще всего API теряют данные не из-за слабого пароля, а из-за того, что сервер не сверил объект с пользователем. Лимиты помогают против перебора, но не против распределённой атаки на отказ в обслуживании.

Четыре сценария и первая мера против каждого

«Взлом API» чаще всего не похож на фильм. Это один из четырёх обыденных сценариев, и у каждого свой первый шаг защиты.

СценарийКак выглядитЧто видно в журналеПервая мера
Подбор входаПеребор паролей и кодов, проверка утёкших пар «адрес — пароль»Серии неудачных входов по одной записи или с одного адресаОграничение попыток по записи и по адресу, одинаковые ответы
Чужие объектыВошедший пользователь меняет номер в запросе и получает чужой заказ или документПодряд идущие запросы к соседним номерамПроверка владельца в каждом методе, тест из-под двух учётных записей
Утёкший ключКлюч партнёра попал в репозиторий, чат или письмоОбращения с чужих адресов и в непривычное времяОтзыв ключа без остановки остальных, ограничение ключа по правам и адресам
Забытый методСтарая версия, отладочный адрес или открытая документация с рабочими примерамиЗапросы к методам, которыми никто не пользуетсяСписок методов, отключение лишнего

Сильный пароль не поможет, если сервер отдаёт чужой заказ любому вошедшему, поэтому важен порядок, а не только набор мер.

Начните со списка методов и потребителей

Нельзя защитить то, чего нет в списке. В большинстве систем рядом с основным API живут то, о чём забыли: прежняя версия, служебные методы для интеграции, которой больше нет, адреса отладки, документация с рабочими запросами. Первая задача — составить таблицу из четырёх столбцов: метод, кто вызывает, как проверяется вход, как проверяются права.

  • Источник списка. Не память разработчиков, а маршруты в коде, настройки обратного прокси и журнал запросов за несколько недель.
  • Потребители. Своё приложение, кабинет, партнёры, внутренние сервисы. Для каждого записывается, чем он аутентифицируется и какие методы реально использует.
  • Лишнее. Метод, которым никто не пользуется, проще отключить, чем защищать. То же с устаревшей версией: назначьте срок и предупредите потребителей, как описано в статье «Проектирование API для интеграций».
  • Публичность документации. Описание API с рабочими примерами нужно партнёрам, а не всему интернету.

Столбец «как проверяются права» к концу работы должен быть заполнен у каждой строки. Пустые клетки в нём и есть список будущих уязвимостей.

Вход: токены, ключи и их срок

Способ входа зависит от потребителя. Универсальных правил два: у каждого доступа есть срок, и его можно отозвать, не ломая остальных.

ПотребительЧто выдатьЧто запретитьЧто записать
Приложение пользователя, кабинетКороткоживущий токен доступа и отдельный токен обновления; выдаёт сервер входаХранить долгоживущий ключ в браузере или мобильном клиентеСрок токена, условия обновления, отзыв при смене пароля и увольнении
Партнёрская интеграцияОтдельный ключ на систему с минимальными правами и срокомОдин ключ на нескольких партнёров или на несколько систем одного партнёраКто выдал, кому, на какие методы, до какой даты
Вебхуки и обмен с партнёромПодпись запроса общим секретом вместе со временем отправкиПринимать запросы без проверки подписи и без окна времениСекрет на партнёра и порядок его замены
Сервис внутри контураВзаимный сертификат или подпись между сервисамиДоверять запросу только потому, что он пришёл из внутренней сетиСрок сертификата, оповещение об истечении

Выбор между простым ключом и токеном выдачи зависит от того, нужен ли вам сервер входа. Если он нужен и для сотрудников, смотрите статью «SSO и MFA: что выбрать»: сервер входа обычно один на все системы. Если у API только партнёры и серверные интеграции, ключей с сроком и правами достаточно.

Хранение и восстановление

Пароли хранятся медленным алгоритмом с солью, ключи в базе лежат в виде хеша, а показываются один раз при создании. Восстановление доступа не должно сообщать, существует ли адрес, а ссылка в письме действует недолго и один раз.

Права: как сделать проверку объекта обязательной

Проверка прав на уровне объекта — главное место, где API теряют данные, потому что она не следует из «входа» сама. Метод может быть открыт только вошедшим, а выбирать заказ по номеру из запроса, не глядя, чей он. Надёжнее всего эту проверку не писать в каждом обработчике заново, а встроить так, чтобы забыть её было трудно.

  • Запрет по умолчанию. Новый метод недоступен никому, пока для него не описаны роли. Забытая проверка тогда выглядит как отказ, а не как открытая дверь.
  • Выборка уже с условием владельца. Объект ищется как «заказ с этим номером в организации пользователя», а не «заказ с этим номером» и потом сравнение. Тогда чужой и несуществующий объект неразличимы, и перебор ничего не показывает.
  • Явный список полей. Что принимаем при сохранении и что отдаём в ответе, задаётся перечнем. Тогда пользователь не может передать поле «роль» или «скидка» и получить запись.
  • Права в одном месте. Матрица «роль — метод — объект» живёт в одном модуле, а не размазана по обработчикам. Так её можно прочитать, проверить и покрыть тестами.
  • Тест из-под двух записей. Каждый метод, принимающий идентификатор, проверяется двумя учётными записями из разных организаций. Такой тест запускается в сборке, и новый метод без него не проходит.

В многопользовательских продуктах это связано с изоляцией данных клиентов; подходы описаны в статье «Мультиарендность в SaaS». Как мы читаем код обработчиков при проверке, описано на странице Secure code review.

Лимиты: что считать и как не ошибиться

Ограничение частоты запросов защищает от подбора и от клиента, который забыл поставить паузу в цикле. Ошибок в его настройке больше, чем в самой идее. Ниже типовые, которые мы видим в чужом коде.

ОшибкаЧто происходитКак исправить
Все запросы считаются с одного адресаСервис стоит за обратным прокси и видит только его адрес: лимит срабатывает на всех пользователей сразу или не срабатывает ни на когоБрать адрес клиента из заголовка, который выставляет ваш прокси, и не доверять заголовку от внешнего клиента
Заголовок подделываетсяЛимит считается по заголовку с адресом, который клиент задаёт сам, и обходится его сменойПринимать такой заголовок только от своего прокси; для входа считать ещё и по учётной записи
Счётчик в памяти одного экземпляраПри нескольких экземплярах сервиса каждый считает свою долю, общий предел в несколько раз выше задуманногоОбщее хранилище счётчиков или ограничение на уровне прокси
Один лимит на всёДорогие выгрузки и дешёвые запросы делят общую квоту, поэтому квота либо мала для обычных, либо велика для тяжёлыхОтдельные квоты на входы, коды, дорогие операции и обычные запросы
Только блокировкаПостоянная блокировка по записи позволяет злоумышленнику вывести из строя чужую учётную записьНарастающая пауза, оповещение владельца и второй фактор
Молчаливый отказКлиент получает пустой ответ или ошибку сервера и повторяет запрос ещё чащеКод 429 и заголовок с временем повтора, чтобы честный клиент подождал

Начните с запаса над реальным использованием по журналу и уменьшайте предел, пока не начнут срабатывать только лишние запросы. И помните о границе: лимит защищает от перебора, но не от распределённой атаки на отказ в обслуживании. Для неё нужны мощности провайдера или сети доставки, и этого мы не делаем.

Ответы и ошибки: что API выдаёт лишнего

Часть утечек происходит не при взломе, а в обычных ответах. Проверьте четыре вещи.

  • Лишние поля. Объект целиком, вместе со служебными полями, внутренними номерами и данными других пользователей. Интерфейс их скрывает, API отдаёт.
  • Подробные ошибки. Текст запроса к базе, пути к файлам и версии программ в сообщении об ошибке помогают тому, кто готовит нападение. Пользователю достаточно кода и короткого понятного текста, остальное в журнал.
  • Различимые ответы. «Нет такого пользователя» и «неверный пароль» подсказывают, какие адреса существуют. Для чужого и несуществующего объекта используйте один ответ.
  • Массовые выборки. Метод списка без предела на размер страницы и без фильтра по организации превращается в выгрузку всей базы.

Защиту от внедрения запросов в базу и подмены содержимого страниц мы разобрали отдельно в статье «SQL-инъекции и XSS простыми словами».

Ключи: жизненный цикл и что делать при утечке

У ключа четыре стадии, и на каждой должен быть ответственный. Если какой-то стадии нет, ключ рано или поздно станет проблемой.

СтадияЧто делаемТипичная ошибка
ВыдачаОтдельный ключ на систему, минимальные права, срок, при необходимости привязка к адресам. Записываем, кто и зачем его получилОдин ключ «на всех» и без срока
ХранениеУ вас в базе только хеш, у потребителя в хранилище секретов, не в репозитории и не в тексте письмаКлюч в коде, в скриншоте, в общем чате
РотацияПлановая замена по сроку; на время замены действуют два ключа сразу, чтобы потребитель успел переключитьсяЗаменить нельзя, не остановив партнёра, поэтому не меняют никогда
ОтзывОтключение конкретного ключа в один шаг, без остановки остальныхОтзыв требует правки кода или перезапуска

Если ключ утёк

  1. Отозвать скомпрометированный ключ и выдать новый по другому каналу, не по тому, где он утёк.
  2. Просмотреть журнал по этому ключу за период, пока он мог быть известен: какие методы вызывались, откуда, какие данные ушли.
  3. Если среди данных были персональные, привлечь юриста и ответственного за обработку данных у вас: уведомления и сроки определяет не разработчик.
  4. Найти, как ключ утёк, и закрыть этот путь. Если он лежал в репозитории, считать скомпрометированными и остальные секреты оттуда: история коммитов хранит удалённое.
  5. Добавить в процесс то, что не сработало: поиск секретов в сборке, срок ключа.

Меры, которые только выглядят как защита

Часть популярных приёмов не защищает или защищает слабее, чем кажется. Они допустимы как дополнение, но не как основа.

  • Скрытый адрес. Адрес метода найдут в приложении, в документации партнёров и в журнале прокси. Секретность адреса не заменяет проверку прав.
  • Случайные идентификаторы. Они затрудняют перебор, но ссылка, которую переслали, откроет объект, если владелец не сверяется.
  • Проверка в интерфейсе. Скрытая кнопка не защищает метод: запрос можно отправить напрямую.
  • Ограничение по адресам как единственная мера. Для закрытых интеграций белый список адресов полезен, но у партнёра адрес меняется, а за общим адресом сидят многие. Нужен ещё и ключ.

Проверочный вопрос к любой мере: что будет, если нападающий знает всё, кроме пароля. Если ответ «ничего страшного», мера работает.

Что делаем мы и с чего начать

Начинаем с обследования: 200 000 ₽ и 2–3 недели за защиту одного API, 350 000 ₽ и 3–4 недели, если API несколько или он связан с обменом между системами. На выходе таблица методов и потребителей, матрица «роль — метод — объект» с результатами прогона, список находок с местом в коде и порядок исправления. Сумма вычитается из первого этапа, если продолжаете с нами. Цены по ступеням собраны на странице «Тарифы».

Дальше по желанию: закрытие найденного (лёгкий пилот 150 000–400 000 ₽ за 2–8 недель) или перестройка модели доступа в нескольких сервисах, а затем сопровождение. Работаем на уровне кода и конфигурации и на копии или тестовом стенде, а не на боевой системе. Не проводим пентест и аттестацию, лицензии ФСТЭК у нас нет, не защищаем от DDoS и не ставим WAF или SIEM как услугу, не дежурим круглосуточно. Код остаётся в вашем репозитории с первого коммита, остановиться можно после любой ступени.

Частые вопросы

С чего начать защиту API?

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

Достаточно ли токена или ключа для защиты API?

Нет. Токен отвечает на вопрос, кто пришёл, а не на вопрос, что ему можно. Без проверки права на каждый объект вошедший пользователь может получить чужие данные. Нужны ещё лимиты и журнал.

Что такое rate limiting и как его настраивать?

Это ограничение числа запросов от клиента за период. Начните с запаса над реальным использованием по журналу, заведите отдельные квоты на входы, коды, дорогие операции и обычные запросы, на превышение отвечайте кодом 429 с указанием времени повтора. Не доверяйте адресу из заголовка, который клиент задаёт сам.

Как защититься от перебора паролей через API?

Ограничение попыток по записи и по адресу с нарастающей паузой, одинаковые ответы для существующего и несуществующего адреса, медленное хеширование паролей, отказ для известных по утечкам паролей и второй фактор для ролей с доступом к деньгам и персональным данным.

Нужен ли отдельный сервер входа?

Нужен, если в компании несколько систем, приложения пользователей и требование второго фактора. Для API только с партнёрскими серверными интеграциями достаточно ключей с сроком и правами. Выбор разобран в статье про SSO и MFA.

Помогает ли rate limiting против DDoS?

Нет. Ограничение частоты защищает от перебора и перегрузки отдельным клиентом. Распределённую атаку на отказ в обслуживании останавливают мощности провайдера или сети доставки. Мы такие меры не предоставляем.

Что делать, если ключ API утёк?

Отозвать ключ, выдать новый по другому каналу, посмотреть журнал за период, пока ключ был известен, закрыть путь утечки и проверить другие секреты оттуда. Если ушли персональные данные, подключить юриста: сроки и уведомления определяет не разработчик.

Сколько стоит проверка защиты API?

Обследование защиты одного API — 200 000 ₽ и 2–3 недели, нескольких — 350 000 ₽ и 3–4 недели. Сумма вычитается из первого этапа, если вы продолжаете с нами. Закрытие найденного оценивается после отчёта.