Чтобы защитить API, нужно закрыть четыре вещи по порядку: составить список всех методов и тех, кто их вызывает, проверить, кто пришёл, проверить его право на каждый объект и ограничить частоту запросов. Остальное (журнал, управление ключами, чистые ответы) делает эти четыре меры наблюдаемыми и управляемыми. Самая дорогая ошибка находится на третьем шаге: человек вошёл, а чужие данные видит.
Статья описывает порядок для небольшой команды, у которой API уже работает. Подробный разбор по слоям с ролями, способами входа и ценами лежит на странице «Защита API от несанкционированного доступа», здесь же только последовательность и ловушки.
Четыре сценария и первая мера против каждого
«Взлом API» чаще всего не похож на фильм. Это один из четырёх обыденных сценариев, и у каждого свой первый шаг защиты.
| Сценарий | Как выглядит | Что видно в журнале | Первая мера |
|---|---|---|---|
| Подбор входа | Перебор паролей и кодов, проверка утёкших пар «адрес — пароль» | Серии неудачных входов по одной записи или с одного адреса | Ограничение попыток по записи и по адресу, одинаковые ответы |
| Чужие объекты | Вошедший пользователь меняет номер в запросе и получает чужой заказ или документ | Подряд идущие запросы к соседним номерам | Проверка владельца в каждом методе, тест из-под двух учётных записей |
| Утёкший ключ | Ключ партнёра попал в репозиторий, чат или письмо | Обращения с чужих адресов и в непривычное время | Отзыв ключа без остановки остальных, ограничение ключа по правам и адресам |
| Забытый метод | Старая версия, отладочный адрес или открытая документация с рабочими примерами | Запросы к методам, которыми никто не пользуется | Список методов, отключение лишнего |
Сильный пароль не поможет, если сервер отдаёт чужой заказ любому вошедшему, поэтому важен порядок, а не только набор мер.
Начните со списка методов и потребителей
Нельзя защитить то, чего нет в списке. В большинстве систем рядом с основным API живут то, о чём забыли: прежняя версия, служебные методы для интеграции, которой больше нет, адреса отладки, документация с рабочими запросами. Первая задача — составить таблицу из четырёх столбцов: метод, кто вызывает, как проверяется вход, как проверяются права.
- Источник списка. Не память разработчиков, а маршруты в коде, настройки обратного прокси и журнал запросов за несколько недель.
- Потребители. Своё приложение, кабинет, партнёры, внутренние сервисы. Для каждого записывается, чем он аутентифицируется и какие методы реально использует.
- Лишнее. Метод, которым никто не пользуется, проще отключить, чем защищать. То же с устаревшей версией: назначьте срок и предупредите потребителей, как описано в статье «Проектирование API для интеграций».
- Публичность документации. Описание API с рабочими примерами нужно партнёрам, а не всему интернету.
Столбец «как проверяются права» к концу работы должен быть заполнен у каждой строки. Пустые клетки в нём и есть список будущих уязвимостей.
Вход: токены, ключи и их срок
Способ входа зависит от потребителя. Универсальных правил два: у каждого доступа есть срок, и его можно отозвать, не ломая остальных.
| Потребитель | Что выдать | Что запретить | Что записать |
|---|---|---|---|
| Приложение пользователя, кабинет | Короткоживущий токен доступа и отдельный токен обновления; выдаёт сервер входа | Хранить долгоживущий ключ в браузере или мобильном клиенте | Срок токена, условия обновления, отзыв при смене пароля и увольнении |
| Партнёрская интеграция | Отдельный ключ на систему с минимальными правами и сроком | Один ключ на нескольких партнёров или на несколько систем одного партнёра | Кто выдал, кому, на какие методы, до какой даты |
| Вебхуки и обмен с партнёром | Подпись запроса общим секретом вместе со временем отправки | Принимать запросы без проверки подписи и без окна времени | Секрет на партнёра и порядок его замены |
| Сервис внутри контура | Взаимный сертификат или подпись между сервисами | Доверять запросу только потому, что он пришёл из внутренней сети | Срок сертификата, оповещение об истечении |
Выбор между простым ключом и токеном выдачи зависит от того, нужен ли вам сервер входа. Если он нужен и для сотрудников, смотрите статью «SSO и MFA: что выбрать»: сервер входа обычно один на все системы. Если у API только партнёры и серверные интеграции, ключей с сроком и правами достаточно.
Хранение и восстановление
Пароли хранятся медленным алгоритмом с солью, ключи в базе лежат в виде хеша, а показываются один раз при создании. Восстановление доступа не должно сообщать, существует ли адрес, а ссылка в письме действует недолго и один раз.
Права: как сделать проверку объекта обязательной
Проверка прав на уровне объекта — главное место, где API теряют данные, потому что она не следует из «входа» сама. Метод может быть открыт только вошедшим, а выбирать заказ по номеру из запроса, не глядя, чей он. Надёжнее всего эту проверку не писать в каждом обработчике заново, а встроить так, чтобы забыть её было трудно.
- Запрет по умолчанию. Новый метод недоступен никому, пока для него не описаны роли. Забытая проверка тогда выглядит как отказ, а не как открытая дверь.
- Выборка уже с условием владельца. Объект ищется как «заказ с этим номером в организации пользователя», а не «заказ с этим номером» и потом сравнение. Тогда чужой и несуществующий объект неразличимы, и перебор ничего не показывает.
- Явный список полей. Что принимаем при сохранении и что отдаём в ответе, задаётся перечнем. Тогда пользователь не может передать поле «роль» или «скидка» и получить запись.
- Права в одном месте. Матрица «роль — метод — объект» живёт в одном модуле, а не размазана по обработчикам. Так её можно прочитать, проверить и покрыть тестами.
- Тест из-под двух записей. Каждый метод, принимающий идентификатор, проверяется двумя учётными записями из разных организаций. Такой тест запускается в сборке, и новый метод без него не проходит.
В многопользовательских продуктах это связано с изоляцией данных клиентов; подходы описаны в статье «Мультиарендность в SaaS». Как мы читаем код обработчиков при проверке, описано на странице Secure code review.
Лимиты: что считать и как не ошибиться
Ограничение частоты запросов защищает от подбора и от клиента, который забыл поставить паузу в цикле. Ошибок в его настройке больше, чем в самой идее. Ниже типовые, которые мы видим в чужом коде.
| Ошибка | Что происходит | Как исправить |
|---|---|---|
| Все запросы считаются с одного адреса | Сервис стоит за обратным прокси и видит только его адрес: лимит срабатывает на всех пользователей сразу или не срабатывает ни на кого | Брать адрес клиента из заголовка, который выставляет ваш прокси, и не доверять заголовку от внешнего клиента |
| Заголовок подделывается | Лимит считается по заголовку с адресом, который клиент задаёт сам, и обходится его сменой | Принимать такой заголовок только от своего прокси; для входа считать ещё и по учётной записи |
| Счётчик в памяти одного экземпляра | При нескольких экземплярах сервиса каждый считает свою долю, общий предел в несколько раз выше задуманного | Общее хранилище счётчиков или ограничение на уровне прокси |
| Один лимит на всё | Дорогие выгрузки и дешёвые запросы делят общую квоту, поэтому квота либо мала для обычных, либо велика для тяжёлых | Отдельные квоты на входы, коды, дорогие операции и обычные запросы |
| Только блокировка | Постоянная блокировка по записи позволяет злоумышленнику вывести из строя чужую учётную запись | Нарастающая пауза, оповещение владельца и второй фактор |
| Молчаливый отказ | Клиент получает пустой ответ или ошибку сервера и повторяет запрос ещё чаще | Код 429 и заголовок с временем повтора, чтобы честный клиент подождал |
Начните с запаса над реальным использованием по журналу и уменьшайте предел, пока не начнут срабатывать только лишние запросы. И помните о границе: лимит защищает от перебора, но не от распределённой атаки на отказ в обслуживании. Для неё нужны мощности провайдера или сети доставки, и этого мы не делаем.
Ответы и ошибки: что API выдаёт лишнего
Часть утечек происходит не при взломе, а в обычных ответах. Проверьте четыре вещи.
- Лишние поля. Объект целиком, вместе со служебными полями, внутренними номерами и данными других пользователей. Интерфейс их скрывает, API отдаёт.
- Подробные ошибки. Текст запроса к базе, пути к файлам и версии программ в сообщении об ошибке помогают тому, кто готовит нападение. Пользователю достаточно кода и короткого понятного текста, остальное в журнал.
- Различимые ответы. «Нет такого пользователя» и «неверный пароль» подсказывают, какие адреса существуют. Для чужого и несуществующего объекта используйте один ответ.
- Массовые выборки. Метод списка без предела на размер страницы и без фильтра по организации превращается в выгрузку всей базы.
Защиту от внедрения запросов в базу и подмены содержимого страниц мы разобрали отдельно в статье «SQL-инъекции и XSS простыми словами».
Ключи: жизненный цикл и что делать при утечке
У ключа четыре стадии, и на каждой должен быть ответственный. Если какой-то стадии нет, ключ рано или поздно станет проблемой.
| Стадия | Что делаем | Типичная ошибка |
|---|---|---|
| Выдача | Отдельный ключ на систему, минимальные права, срок, при необходимости привязка к адресам. Записываем, кто и зачем его получил | Один ключ «на всех» и без срока |
| Хранение | У вас в базе только хеш, у потребителя в хранилище секретов, не в репозитории и не в тексте письма | Ключ в коде, в скриншоте, в общем чате |
| Ротация | Плановая замена по сроку; на время замены действуют два ключа сразу, чтобы потребитель успел переключиться | Заменить нельзя, не остановив партнёра, поэтому не меняют никогда |
| Отзыв | Отключение конкретного ключа в один шаг, без остановки остальных | Отзыв требует правки кода или перезапуска |
Если ключ утёк
- Отозвать скомпрометированный ключ и выдать новый по другому каналу, не по тому, где он утёк.
- Просмотреть журнал по этому ключу за период, пока он мог быть известен: какие методы вызывались, откуда, какие данные ушли.
- Если среди данных были персональные, привлечь юриста и ответственного за обработку данных у вас: уведомления и сроки определяет не разработчик.
- Найти, как ключ утёк, и закрыть этот путь. Если он лежал в репозитории, считать скомпрометированными и остальные секреты оттуда: история коммитов хранит удалённое.
- Добавить в процесс то, что не сработало: поиск секретов в сборке, срок ключа.
Меры, которые только выглядят как защита
Часть популярных приёмов не защищает или защищает слабее, чем кажется. Они допустимы как дополнение, но не как основа.
- Скрытый адрес. Адрес метода найдут в приложении, в документации партнёров и в журнале прокси. Секретность адреса не заменяет проверку прав.
- Случайные идентификаторы. Они затрудняют перебор, но ссылка, которую переслали, откроет объект, если владелец не сверяется.
- Проверка в интерфейсе. Скрытая кнопка не защищает метод: запрос можно отправить напрямую.
- Ограничение по адресам как единственная мера. Для закрытых интеграций белый список адресов полезен, но у партнёра адрес меняется, а за общим адресом сидят многие. Нужен ещё и ключ.
Проверочный вопрос к любой мере: что будет, если нападающий знает всё, кроме пароля. Если ответ «ничего страшного», мера работает.
Что делаем мы и с чего начать
Начинаем с обследования: 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 недели. Сумма вычитается из первого этапа, если вы продолжаете с нами. Закрытие найденного оценивается после отчёта.