Перейти к содержанию

Webhooks: безопасность

Что делаем мы

Подпись HMAC-SHA256

Каждый webhook содержит заголовок X-Truenum-Signature: t=<ts>,v1=<hex>. Без проверки подписи нельзя доверять телу — атакующий, узнавший ваш webhook_url (а это не секретная информация), сможет отправить поддельный POST. Полная инструкция: Подпись.

SSRF-защита webhook_url

При создании верификации мы валидируем URL:

  • Схема — только http или https.
  • Хост — только публичный IP / DNS-имя, резолвящееся в публичный IP.
  • Запрещены: 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16 (link-local), ::1, fc00::/7, fe80::/10, а также 0.0.0.0.
  • Запрещены любые DNS-имена, резолвящиеся в приватный диапазон.

Если URL не проходит проверку — 400 Bad Request с конкретным сообщением.

Анти-DNS-rebind

DNS-имя может разрешиться в публичный IP в момент валидации и в приватный в момент доставки. Поэтому валидация выполняется дважды: при POST /verifications/ и непосредственно перед каждой попыткой доставки. На стороне нашей инфраструктуры использование requests + custom HTTPAdapter гарантирует resolve-once и проверку финального IP перед открытием соединения.

Таймаут

Мы ждём ответа 10 секунд. Дольше — закрываем соединение, считаем попытку проваленной (см. Ретраи).

User-Agent

User-Agent: TrueNum/1.0. Идентифицирует нас в логах и позволяет вам whitelisted'ить только реальный трафик (но не используйте User-Agent для аутентификации — его легко подделать; полагайтесь на подпись).

Egress IP

Мы можем менять egress-IP без предупреждения. Не whitelisted'те IP для аутентификации входящих webhook'ов — используйте подпись.

Что должны делать вы

Проверка подписи

Обязательно. Подробно — Подпись.

Защита от replay

Сравните t (timestamp в подписи) с текущим временем. Если разница

5 минут — отклоните. Это защищает от reply-атак злоумышленником, у которого есть запись валидного webhook'а.

HTTPS

webhook_url должен быть HTTPS. Сертификат — валидный (не self-signed), выданный публичной CA. Это защищает тело + подпись от прослушки/модификации на сетевом уровне.

Идемпотентность приёма

См. Ретраи. Один и тот же webhook может прилететь несколько раз — ваш обработчик должен быть готов.

Аутентификация эндпоинта на вашей стороне

Webhook-эндпоинт должен быть публичным (ниже — почему). При этом аутентификация осуществляется через подпись webhook'а, не через бэйсик-ауф / OAuth. Не выдавайте webhook-эндпоинт за приватный ресурс с защитой по сети — это противоречит SSRF-протоколу: мы специально отказываемся ходить в приватные сети.

Не парсите JSON до проверки подписи

Парсер JSON — тоже потенциальная attack-surface (особенно в нестрого-типизированных языках). Сначала проверьте подпись, потом парсите.

Логирование

Логируйте каждый прилетевший webhook (включая отброшенные по подписи) с: timestamp, hash подписи, размер тела, ваш ответ. Без тела — тела могут содержать персональные данные. Срок хранения — по вашему compliance.

Чего НЕ делаем

  • Не указываем webhook_url или содержимое тела в общедоступных логах TrueNum. Журнал доставок виден только владельцу аккаунта в дашборде.
  • Не отправляем client_ref или phone третьим сторонам. Они возвращаются только в ваш webhook_url.
  • Не следуем HTTP-редиректам (3xx → ретрай как ошибка). webhook_url должен быть финальным.

Если подозреваете компрометацию

  1. Ротируйте webhook secret в дашборде — старый секрет инвалидируется немедленно. Все приходящие webhook'и теперь подписываются новым.
  2. Обновите секрет на стороне приёмника.
  3. Просмотрите дашборд WebhooksDeliveries — есть ли аномальные 2xx-ответы от чужой инфраструктуры (это возможно только если злоумышленник перехватил webhook_url, что само по себе требует расследования).
  4. Если подозреваете утечку API-ключа — ротируйте и его (см. Аутентификация).