АналитикаСистемный анализСистемный аналитик по интеграциям

Сторонняя система присылает вебхуки через интернет. Как получателю проверить подлинность уведомления до его...

Сторонняя система присылает вебхуки через интернет. Как получателю проверить подлинность уведомления до его обработки?

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

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

Такая проверка подтверждает, что запрос сформирован стороной, владеющей секретом, и не был изменён по пути. HTTPS защищает канал передачи, но сам по себе не заменяет проверку подписи и защиту от повторной доставки.

Исторический контекст

Интеграции между системами изначально часто строились на доверии к сетевому адресу, закрытому каналу или простому ключу в заголовке. Эти подходы плохо защищают от подмены содержимого: наличие ключа не доказывает, что тело запроса не изменили, а перехваченный запрос можно повторить.

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

Постановка проблемы

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

Проверка только IP-адреса ненадёжна: адреса могут изменяться, запрос может приходить через промежуточные узлы, а доверенная сеть не гарантирует подлинность содержимого. Проверка только HTTPS подтверждает защищённость конкретного соединения, но не решает задачу аутентификации отправителя на уровне сообщения и не препятствует повторной обработке уже принятого запроса.

Подробное решение

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

Получатель действует в таком порядке:

  1. Проверяет наличие обязательных метаданных и допустимость метки времени относительно своих часов.
  2. Использует именно исходное тело запроса, не пересериализуя JSON и не меняя кодировку пробелами, порядком полей или переводами строк.
  3. Вычисляет HMAC тем же алгоритмом и секретом.
  4. Сравнивает вычисленную и полученную подписи безопасным сравнением, не зависящим от места первого несовпадения.
  5. Проверяет уникальность идентификатора события в заданном окне времени и отклоняет уже обработанное событие.

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

HMAC не шифрует содержимое и не скрывает секрет в запросе. Он подтверждает знание общего секрета, поэтому секрет нельзя передавать клиенту, хранить в журналах или помещать в URL. При компрометации секрета нужна его замена; на переходный период система может поддерживать текущий и предыдущий секреты, явно ограничивая срок такой совместимости.

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

Ситуация из практики

Платёжный провайдер отправлял уведомление о завершении платежа. Команда рассматривала три варианта: разрешить запросы только с известных IP-адресов, передавать постоянный ключ в заголовке или использовать HMAC с временной меткой и идентификатором события.

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

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

Что кандидаты часто упускают

  1. Допустимо ли проверять подпись после разбора JSON?

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

  1. Защищает ли HMAC от повторной доставки сообщения?

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

  1. Почему нельзя считать наличие секрета достаточным доказательством личности отправителя?

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