Сторонняя система присылает вебхуки через интернет. Как получателю проверить подлинность уведомления до его обработки?
Получатель должен проверять цифровую подпись запроса, обычно вычисленную отправителем по телу сообщения и дополнительным метаданным с использованием общего секрета. Для схемы на основе HMAC получатель заново вычисляет подпись по исходным байтам тела, сравнивает её с переданной константным по времени сравнением и отклоняет запросы с просроченной меткой времени или повторным идентификатором.
Такая проверка подтверждает, что запрос сформирован стороной, владеющей секретом, и не был изменён по пути. HTTPS защищает канал передачи, но сам по себе не заменяет проверку подписи и защиту от повторной доставки.
Интеграции между системами изначально часто строились на доверии к сетевому адресу, закрытому каналу или простому ключу в заголовке. Эти подходы плохо защищают от подмены содержимого: наличие ключа не доказывает, что тело запроса не изменили, а перехваченный запрос можно повторить.
Подписывание сообщений появилось как практический способ проверять целостность и происхождение данных поверх недоверенной сети. Отправителю и получателю не требуется постоянное соединение или общая инфраструктура доверия: достаточно согласовать алгоритм, формат подписываемых данных и управление секретами.
Вебхук может пройти через интернет, прокси, балансировщики и очереди. Атакующий способен отправить поддельное уведомление, изменить тело легитимного запроса или повторить ранее перехваченное сообщение, например повторно создать заказ или изменить его статус.
Проверка только IP-адреса ненадёжна: адреса могут изменяться, запрос может приходить через промежуточные узлы, а доверенная сеть не гарантирует подлинность содержимого. Проверка только HTTPS подтверждает защищённость конкретного соединения, но не решает задачу аутентификации отправителя на уровне сообщения и не препятствует повторной обработке уже принятого запроса.
Отправитель и получатель заранее согласуют общий секрет. Отправитель вычисляет, например, HMAC по комбинации версии схемы, метки времени, уникального идентификатора события и исходного тела запроса, затем передаёт подпись и эти метаданные в заголовках.
Получатель действует в таком порядке:
Подпись должна покрывать не только тело, но и данные, которые участвуют в защите от повторной доставки. Если подписать только тело, злоумышленник не сможет его изменить, но сможет многократно отправлять тот же корректный запрос. Для защиты от повторов обычно хранят идентификаторы событий с ограниченным сроком жизни; это требует согласовать период хранения и поведение при задержанных доставках.
HMAC не шифрует содержимое и не скрывает секрет в запросе. Он подтверждает знание общего секрета, поэтому секрет нельзя передавать клиенту, хранить в журналах или помещать в URL. При компрометации секрета нужна его замена; на переходный период система может поддерживать текущий и предыдущий секреты, явно ограничивая срок такой совместимости.
Подпись проверяют до бизнес-обработки и до постановки сообщения в доверенную очередь, если очередь может принимать данные от недоверенного источника. При неверной подписи обычно возвращают ошибку аутентификации или используют согласованный с поставщиком ответ; повторную доставку корректно подписанного, но уже обработанного события следует сделать идемпотентной на уровне обработки.
Платёжный провайдер отправлял уведомление о завершении платежа. Команда рассматривала три варианта: разрешить запросы только с известных IP-адресов, передавать постоянный ключ в заголовке или использовать HMAC с временной меткой и идентификатором события.
Фильтрация по IP была простой, но требовала постоянного обновления списка и не защищала тело от изменений после прохождения сетевого фильтра. Постоянный ключ позволял подтвердить наличие секрета, однако не обеспечивал целостность тела и не предотвращал повторную отправку перехваченного запроса.
Выбрали HMAC по метке времени, идентификатору события и исходному телу, а идентификаторы успешно обработанных событий стали хранить ограниченное время. Это позволило отклонять изменённые и просроченные сообщения, обнаруживать повторы до повторного изменения платежа и безопасно менять секреты без остановки интеграции.
Нет, если подпись рассчитана по исходному представлению тела. Два JSON-документа могут иметь одинаковый смысл, но различаться пробелами, порядком полей, экранированием или кодировкой. После разбора и повторной сериализации получатель может получить другие байты и ошибочно отклонить легитимное сообщение либо, при нестрогой схеме каноникализации, создать неоднозначность. Надёжнее сохранять исходное тело и подписывать именно его; альтернативой является заранее строго определённая каноникализация.
Нет. Повторно отправленное неизменённое сообщение будет иметь корректную подпись. Поэтому в подписываемые данные включают временную метку или срок действия, а получатель хранит идентификатор события либо отпечаток сообщения и отклоняет уже обработанные значения. Это не отменяет идемпотентность бизнес-операции: запись о факте обработки может быть потеряна при сбое, поэтому изменение состояния и фиксацию идемпотентного ключа нужно проектировать согласованно.
При общем секрете обе стороны способны создать корректную подпись. Если один и тот же секрет используется несколькими отправителями, получатель подтверждает лишь принадлежность к общей группе, но не конкретному источнику. Для строгой идентификации отдельных отправителей применяют разные секреты на интеграцию или асимметричные подписи: отправитель использует закрытый ключ, а получатель проверяет подпись публичным ключом и может связать ключ с конкретным источником через доверенную инфраструктуру.