Эта статья является переводом моей английской статьи которую можно прочитать здесь. Заранее извиняюсь за возможные неточности в компьютерной терминологии на русском языке.
Интерфейсы прикладного программирования или API отвечают за большую часть системной интеграции и функциональных компонентов современного вычислительного ландшафта как в потребительской, так и в корпоративной среде.
Правильно сконструированные безопасные API обеспечивают значительные преимущества при создании новой системы, интеграции с другими системами и на протяжении всего жизненного цикла приложения.
Основываясь на опыте автора при внедрении API для различных клиентов в финансовом, страховом, телекоммуникационном и государственном секторах, безопасность часто упускается из виду в пользу упрощенной реализации для конкретного поставщика/продукта, что затрудняет интеграцию и приводит к дополнительным расходам на поддержку и внедрение новых функций.
В этой статье рассматриваются методы проектирования безопасности API в нейтральной для продукта манере, чтобы помочь архитекторам планировать и создавать простые в работе и безопасные API.
Рекомендуемый подход — отделить безопасность API от его бизнес-функций и позволить бэкэнд-разработчикам сосредоточиться только на бизнес-функциях. Когда бизнес-логика для API готова, ее можно опубликовать с помощью общих компонентов безопасности, описанных в этой статье.
В этой статье не даются какие-либо рекомендации по конкретному продукту, но любая современная платформа безопасности/управления API сможет удовлетворить большинство предлагаемых требований, используя имеющиеся стандартные функции.
API трафик
Типичный поток трафика для API представлен на диаграмме ниже:
Клиент (обычно это приложение) отправляет запрос на определенную конечную фунцию API с необходимым типом аутентификации/авторизации, который затем направляется в бизнес сервис, где происходит фактическая обработка запроса. Как показано на диаграмме, безопасность и дополнительные функции обработки запросов/ответов находятся за пределами бизнес-функций.
Рекомендуемый подход состоит в том, чтобы иметь набор стандартных функций, которые улучшат безопасность API, удобство использования и лучше защитят серверные бизнес-сервисы. API безопасность обеспечивается следующими стандартными компонентами:
Рассмотрим предложенные функции более детально:
Описание API
Эта функция предоставляет клиенту возможность запрашивать описания API в машиночитаемом (YAML, XML, JSON) или в формате ориентированном на человека (HTML) с помощью простого HTTP-вызова GET.
Технически это не компонент безопасности API, но это очень полезная функция, которая может значительно упростить использование API и уменьшить усилия по интеграции. Наличие как человеко-, так и машиночитаемой документации в самом API является полезным ресурсом для тех, кто ищет техническую информацию об API, образцы запросов/ответов, схемы JSON и XML и другую информацию.
Клиент может запросить описание API в различных форматах для автоматической настройки кода или для проверки функциональности разработчиком.
В следующей таблице представлены возможные форматы запросов и соответствующие ответы:
Формат запроса (HTTP запрос) | Формат ответа |
?yaml | OpenAPI описание в YAML |
?json | OpenAPI описание в JSON |
?wsdl | API веб сервис WSDL в формате XML |
?wadl | API rest сервис WADL в формате XML |
?html | OpenAPI описание в формате HTML |
?soap | WSDL описание в формате HTML |
?rest | WADL описание в формате HTML |
Машиночитаемые описания API (OpenAPI, WSDL, WADL) обычно загружаются в API на этапе разработки кода, а версии в HTML могут создаваться автоматически во время запроса путем преобразования из машиночитаемых версий или также могут быть закодированы в API в тех случаях, когда автоматическое преобразование нецелесообразно.
Например, существует несколько бесплатных шаблонов XSL, которые можно использовать для автоматического преобразования документов WSDL или WADL в удобные для чтения HTML-версии. Описания OpenAPI JSON или YAML также могут быть представлены в удобочитаемом формате HTML с использованием различных инструментов, таких как редактор Swagger.
В некоторых случаях эта функциональность может быть предоставлена путем интеграции API с порталом, но для целей данного документа мы оставим ее на уровне API без привлечения внешних систем или дополнительных компонентов.
Проверка типа содержимого запроса
Проверка типа содержимого запроса — это первый шаг проверки безопасности. Это необходимо для того, чтобы сообщения запроса неправильного формата не попадали в бизнес сервис. Это также позволяет другим проверкам безопасности определять, какой формат сообщения об ошибке потребуется в ответе, если какая-либо из проверок запроса не будет удовлетворена.
Для типичного API допустимым типом содержимого запроса является application/json для REST JSON, application/xml для REST/XML и text/xml для SOAP.
Установка соединения TLS
Рекомендуется шифровать трафик запросов и ответов API для защиты конфиденциальности информации при передаче по незащищенным сетям. Общепринятой практикой является использование протокола шифрования SSL/TLS.
Обеспечение безопасности должно включать следующие шаги:
Проверка того, что трафик поступает через туннель TLS и использует последнюю версию протокола
Туннель TLS использует безопасный набор шифров, цифровых подписей и хеш-функций. Это требование зависит от технологии и потребует тщательного выбора наиболее безопасных параметров, поддерживаемых сервером и всеми клиентами, которым необходимо будет подключиться к API.
При необходимости может быть использована проверка сертификата клиента для двусторонних туннелей TLS.
Авторизация запроса
Эта функция будет аутентифицировать и авторизовывать входящие запросы API, используя соответствующие методы аутентификации или их комбинацию:
Идентификатор пользователя/пароль (напрямую или через системы безопасности, такие как WS-Security)
Ключ API
Сертификат клиента
Федеративный документ (SAML, JWT OIDC)
OAuth
Не рекомендуется использовать систему безопасности API для хранения любых данных клиентов, она должена полагаться на внешнюю службу аутентификации, где должны быть установлены соответствующие функции для хранения информации о клиентах, их пароли и другие функции безопасности.
Проверка содержимого запроса
Эта функция проверяет, что содержимое запроса не содержит опасных с точки зрения безопасности компонентов, прежде чем передать ее бизнес сервису. Типы выполняемых здесь проверок будут зависеть от формата запроса (XML или JSON) и могут включать следующие элементы:
Проверка структуры документа JSON (длина объекта, количество записей объекта, количество записей массива, длина имени записи)
Структура XML-документа (длина непрерывного текста, длина значения атрибута, длина имени атрибута, глубина вложения элементов)
Распространенные атаки SQL-инъекций в теле сообщения запроса, URL-адресе запроса и строке запроса URL-адреса запроса
Обнаружение другой информации в теле запроса которые могут быть использованы для внедрения команд ОС, LDAP и т. п.
Проверка безопасности полезной нагрузки для конкретного приложения
Эти проверки необходимы для защиты бизнес сервиса и данных от атак использующих содержимое запроса.
Проверка HTTP метода
Эта функция проверит, что запрос API получен с использованием правильного метода HTTP (GET, POST, PUT и т. д.). Один и тот же API может обеспечивать поддержку нескольких методов и операций, поэтому при этой проверке может потребоваться учитывать другие параметры запроса, такие как URL-адрес запроса и строку HTTP-запроса.
Проверка скорости запросов
Эта функция будет проверять глобальную скорость запросов API или конкретную скорость для запрошенной операции API. Эта проверка обеспечивает защиту бизнес сервиса от атак типа «отказ в обслуживании» или просто ограничивает скорость запросов, чтобы защитить их от перегрузки.
Скорость сообщений можно настроить как количество одновременных сообщений в секунду или за указанный период времени для поддержки квот API на клиента.
Проверка размера запроса
Эта функция проверит, что размер полезной нагрузки запроса не превышает ограничения для запрошенной операции API. Очень важно предотвратить попадание неправильных (больших) запросов к бизнес сервису, поскольку это может привести к множеству нежелательных проблем.
В большинстве случаев типичная полезная нагрузка запроса должна быть меньше нескольких килобайт, если для работы по каким-то специфическим причинам не требуется более крупная полезная нагрузка.
Проверка схемы запроса
Эта функция проверяет полезную нагрузку запроса на соответствие соответствующему документу схемы XML или JSON, чтобы убедиться, что запрос семантически корректен для запрошенной операции API.
Поскольку проверка схемы запроса может интенсивно использовать ЦП, ее проверка здесь может удалить эти операции из бизнес сервиса и убедиться, что данные в запросе построены правильно, прежде чем они достигнут бизнес сервис.
Очевидно, что в случаях, когда принимается несколько форматов запросов, API должна быть настроена на использование правильной схемы в зависимости от типа полезной нагрузки запроса (XML или JSON).
Преобразование запроса
Эта необязательная функция поддерживает те случаи использования, когда полезные данные запроса должны быть преобразованы в формат, необходимый для бизнес сервиса. Например, когда клиент отправит запрос в формате JSON из AJAX приложения на основе браузера или мобильного приложения, и его необходимо будет преобразовать в XML-запрос в формате SOAP, поддерживаемый бизнес сервисом.
Соединение с бизнес сервисом
Эта функция поддерживает подключение и обмен данными с бизнес сервисом на сетевом уровне и уровне приложения. Это необходимо для информирования клиента о любых проблемах с подключением, возникающих во время сетевых подключений или подключений на уровне приложений. Мы обсудим более подробную информацию при обсуждении конфигураций времени ожидания подключения позже в этом документе. Как правило, эта функция отвечает клиенту сообщением об ошибке и кодом ошибки HTTP 503, чтобы указать, что соединение с серверной системой не удалось.
Проверка ответа бизнес сервиса
Эта необязательная функция позволяет проверять ответ бизнес сервиса. В большинстве случаев ответ может быть сразу отправлен обратно клиенту, кроме случев когда его нужно каким-то образом проверить перед возвратом.
Преобразование ответа
Эта необязательная функция необходима, когда внутренний формат ответа необходимо преобразовать в другой формат сообщения, понятный клиенту. Подобно преобразованию запроса, эту функцию можно использовать для преобразования XML-ответа SOAP в JSON перед его отправкой клиенту.
Проверка дополнительных условий
Это необязательная функция, которая может проверить любое дополнительное условие на случай, если потребуется применить дополнительную логику в дополнение к стандартным фунциям.
Конфигурация тайм-аута
Правильно настроенные тайм-ауты службы очень важны для корректной обработки ошибок и устранения неполадок. Они очень часто игнорируются или неправильно настраиваются, что приводит к многочисленным проблемам и перебоям в работе API.
Правильная конфигурация тайм-аута системы не должна допускать тайм-аута подключения клиента до того, как произойдет тайм-аут системы к которой он пытается подключиться:
В этой конфигурации значение тайм-аута чтения системы API безопасности должно быть, как минимум, на одну секунду выше, чем значение тайм-аута бизнес сервиса, а значение тайм-аута чтения клиента должно быть,как минимум, на две секунды больше, чем значение тайм-аута бизнес сервиса.
Если тайм-ауты настроены неправильно, то в некоторых случаях корректные ответы от бизнес сервиса и/или системы безопасности API будут потеряны, что приведет к сбою клиентского приложения.
Обработка ошибок
Значительная часть логики безопасности API посвящена правильной обработке ошибок, что помогает в интеграции клиентских приложений и быстрому устранению неполадок.
Коды ошибок для безопасности API настраиваются с использованием соответствующих кодов ошибок HTTP 400 и 500, как показано на блок-схеме выше.
Очевидно, что ответы об ошибках должны быть в формате, соответствующем полученному запросу. Для запроса SOAP потребуется формат ошибки SOAP, для REST/XML и REST/JSON потребуются ошибки XML и JSON соответственно.
Ответы об ошибках должны быть информативными и предоставлять достаточно информации для устранения неполадок, но не раскрывать конфиденциальную информацию клиентам, не имеющим авторизованного доступа.
Как минимум, каждый ответ об ошибке должен содержать следующую информацию:
Описание API и вызываемой операции
Код ошибки
Происхождение ошибки и описание с соответствующими подробностями
Время ошибки в удобочитаемом формате
Уникальный идентификатор транзакции сообщения
Важно различать ошибки системы безопасности API и ошибки бизнес сервиса. Во многих случаях система безопасности API успешно обрабатывает запрос, но бизнес сервис возвращает ошибку.
Один из рекомендуемых способов разделения ошибок системы безопасности API и внутренних ошибок бизнес сервиса это использование отдельных пространств имен в XML и JSON для системы безопасности API и бизнес сервиса. Таким образом, будет очевидно, какая система отвечает с ошибкой.
Ниже приведены примеры сообщений об ошибках в формате XML и JSON с четкой идентификацией того, что они исходят от системы безопасности API (APISEC):
<?xml version="1.0" encoding="UTF-8"?>
<APISEC>
<Status>
<code>401</code>
<message>Unauthorized – client failed to present valid api key</message>
<api>Get Customer Detail</api>
<id>0000015e5892aaa3-23a3</id>
<time>Wed Sep 13 04:44:01 2017</time>
</Status>
</APISEC>
{
"APISEC":{
"Status":{
"code":"401",
"message":"Unauthorized – client failed to present valid api key using SSL/TLS connection",
"api":"Get Customer Detail",
"id":"0000015e5892aaa3-23a5",
"time":"Wed Sep 13 04:45:18 2017"
}
}
}
Регистрация событий системы безопасности API
Ведение журнала событий системы безопасности API является важным компонентом поддержки необходимым для устранения неполадок системы, анализа производительности API и исторических тенденций.
Каждая платформа безопасности API имеет свой собственный набор событий безопасности и производительности, но следующие минимальные параметры являются общими и должны записываться для каждой транзакции:
Идентификатор сообщения (успех/ошибка)
Отметка времени в формате ISO8601 (для взаимодействия с внешними системами)
URL-адрес запроса
URL-адрес бизнес сервиса
HTTP-метод запроса
Тип содержимого запроса HTTP
HTTP код ответа на сообщение, отправленный клиенту
Описание сообщения об ошибке/успехе
Имя/операция API
ID аутентифицированного пользователя
Время между запросом и ответом
IP-адрес клиента
Уникальный идентификатор транзакции (система безопасности API обычно генерирует его автоматически для каждого сообщения)
Текущее ограничение скорости для API
Размер сообщения запроса
Размер ответного сообщения
Могут быть включены дополнительные параметры, характерные для используемой технологии безопасности API
Системы безопасности API
Современные платформы безопасности API включают в себя локальные системы, такие как MuleSoft Anypoint, IBM DataPower SOA Gateway, шлюз API Broadcom Layer7, шлюз API OKTA Kong и другие, предназначенные для реализации всех функций, описанных в этом документе.
Для развертывания облачных API все основные поставщики облачных услуг (Azure, AWS, GCP) имеют облачные компоненты управления API, которые также могут поддерживать большинство необходимых функций.
Рекомендуется использовать только готовые функции вышеперечисленных платформ, избегая запуска пользовательского кода, поскольку это противоречит цели создания отдельной системы, управляемой безопасностью API, с низкими затратами на настройку и поддержку.
Антипаттерны безопасности API
В заключение я хотел бы привести примеры плохой практики, связанной с реализацией безопасности API.
Следует избегать следующих технологий в рамках безопасности API:
Управление сеансами приложений, требующее создания и хранения постоянных сеансов в системе безопасности API
Обработка сообщений с сохранением состояния. Любая обработка сообщений с отслеживанием состояния на шлюзе безопасности API потребует хранения и извлечения атрибутов сообщения на платформе шлюза API, что может поставить под угрозу его производительность и управляемость. В некоторых особых случаях шлюз может использоваться для защиты от повторного воспроизведения сообщений с использованием кэш-памяти.
Асинхронная обработка сообщений. Асинхронный поток сообщений требует, чтобы API-шлюз генерировал постоянные идентификаторы сообщений и обрабатывал асинхронные ответы, что не является естественной функцией платформы API-шлюза и должно быть предоставлено для обработки на сервисной шине.