Вопрос или проблема
Чтобы позволить пользователям API проверять подлинность исходящих вебхуков, я использую модель, аналогичную Slack:
-
Конкатенировать временную метку и тело, HMAC с предустановленным ключом, добавить временную метку и HMAC дайджест в заголовки.
-
Получатель делает то же самое и сравнивает с дайджестом в заголовке.
Я могу реализовать это исключительно для исходящих вебхуков или могу реализовать это как промежуточное ПО, которое выполняет этот процесс как для исходящих вебхуков, так и для ответов на запросы.
Является ли последний вариант хорошей практикой? Хорошей идеей?
Это плохая идея.
Вы фактически (зло)употребляете симметричной криптографией для реализации асимметричной криптографии. В вашем подходе возникнут следующие проблемы:
- Если у вас есть только один ключ, то каждый клиент, которому вы передадите ключ, может эффективно выдавать себя за вас
- Если у вас есть один ключ на клиента, вам необходимо заботиться о генерации ключей, хранении, обмене, устаревании и т.д.
Гораздо лучшая идея заключалась бы в использовании любой асимметричной криптографической системы (эллиптические кривые, RSA и т.д.). Схема будет работать следующим образом:
- Вы генерируете пару приватного и публичного ключей и распространяете публичный ключ.
- Вы подписываете временную метку и тело, а затем отправляете это вашим клиентам.
- Клиенты используют ваш публичный ключ для проверки подписи, и таким образом подлинности и целостности сообщения.
Предполагая, что вы используете HTTPS (или другой протокол, защищенный TLS или аналогичной безопасностью), вам не нужно подписывать ответы. Цель подписи — защитить целостность сообщения (что уже обеспечивается TLS) и аутентифицировать отправителя сообщения (что также уже обеспечивается TLS). Имеет смысл подписывать запросы, потому что по умолчанию HTTPS аутентифицирует только сервер (сторону, которая получает запросы и отправляет ответы).
Вот почему, когда вы входит в Google или аналогичный сервис, вы предоставляете свои учетные данные (имя пользователя + пароль + любые дополнительные факторы), но сервер не обязан добавлять никакую подпись к своим ответам, которую вам затем необходимо проверить. Аутентификация сервера осуществляется на уровне TLS, между вашим браузером (или другим клиентом) и их сервером.
Аутентификация клиента в HTTPS возможна и будет существенно более безопасной, чем схема подписания, которую вы используете в настоящее время. Это известно как “взаимный TLS” (или просто “mTLS”) или “TLS с клиентскими сертификатами”, и требует, чтобы клиент (в данном случае, ваше программное обеспечение, генерирующее вызовы вебхуков; даже если вы рассматриваете это как “сервер”, это клиент для целей этих запросов) аутентифицировался на серверах пользователей с использованием своего сертификата. Серверы пользователя должны быть настроены на ожидание этого сертификата, что поддерживает почти все серверные программные обеспечения, но иногда это бывает непросто настроить. Тем не менее, это обеспечивает лучшую защиту, чем описанная вами система, без необходимости в том, чтобы другая сторона могла выдать себя за вас, или чтобы у вас был уникальный предустановленный ключ для каждого пользователя.
Ответ или решение
Нужно ли подписывать исходящие ответы при использовании HMAC для вебхуков?
При проектировании системы, использующей вебхуки, важным аспектом является обеспечение подлинности и целостности сообщений. Ваша текущая реализация, основанная на HMAC, позволяет пользователям проверять подлинность исходящих вебхуков, что является хорошей практикой. Однако важно рассмотреть необходимость подписывать также и исходящие ответы.
Основные доводы против подписывания исходящих ответов
-
Безопасность через TLS: Если вы используете HTTPS (или аналогичный протокол с защитой TLS), необходимость в подписывании исходящих ответов снижается. TLS уже обеспечивает аутентификацию сервера и целостность передаваемого сообщения. Это значит, что клиент может быть уверен в том, что ответ поступает от доверенной сущности, и что он не был изменен во время передачи.
-
Сложность реализации: Добавление подписей к исходящим ответам может усложнить интерфейс API. Каждый ответ должен будет формировать и передавать подпись, что увеличивает объем данных и время обработки. Это особенно важно в системах с высоким трафиком, где задержки должны быть минимальными.
-
Составные задачи аутентификации: Подписывание запросов имеет смысл, поскольку оно защищает целостность данных и аутентифицирует отправителя вебхука. Однако для исходящих ответов существует другой уровень аутентификации, связанный с защищённым соединением.
Альтернативные подходы к аутентификации
Рекомендуется рассмотреть использование асимметричной криптографии, такой как RSA или эллиптические кривые, для повышения безопасности системы. Применение пары ключей (приватного и публичного) уменьшает риски, связанные с обменом предназанченных ключей. Принципы использования могут быть следующими:
- Генерация пары ключей: Создайте пару ключей и распостраните только публичный ключ среди клиентов.
- Подписание сообщений: Используйте приватный ключ для подписания каждого сообщения (включая вебхуки).
- Проверка на клиентской стороне: Клиенты используют публичный ключ для верификации подписи и тем самым подтверждают подлинность сообщения.
Заключение
Следовательно, подписывать исходящие ответы не имеет смысла, если соединение уже защищено с помощью TLS. Лучшей практикой будет соблюдение аутентификации запросов с использованием HMAC для вебхуков, а также использование асимметричной криптографии для подписывания сообщений, если ваша система требует более высокой степени доверия. Это обеспечит устойчивость системы к атакам и поможет избежать случайных уязвимостей, связанных с обработкой подписи для каждого ответа.
Данный подход поможет вам не только повысить уровень безопасности вашего API, но и создать более простую и эффективную архитектуру взаимодействия.