Разработка · 6 мин чтения

Авторизация вебхуков в n8n: заголовки и секретные токены

Вебхук в n8n по умолчанию открыт для любого, кто узнал URL - и это не теоретическая дыра, а то, с чем я регулярно сталкиваюсь на аудите чужих сценариев. Настроить n8n webhook авторизацию можно за 10-15 минут, если понимать разницу между Basic Auth в Webhook-ноде, проверкой секретного токена в заголовке и HMAC-подписью тела запроса. Дальше разберу все три варианта на живых кейсах: Telegram-бот, который раньше был написан на aiogram и слушал обновления сам, вебхуки Т‑Банка и СДЭК с подписью в теле, и кастомный скрипт на Tilda, который дёргает n8n напрямую.

Почему открытый вебхук в n8n - это не мелочь

URL вебхука в n8n выглядит как случайная строка, но это не защита, а обфускация. Если сценарий пишет заказы в CRM, шлёт сообщения в Telegram или списывает токены у платного API, любой, кто нашёл или подсмотрел ссылку - в логах браузера, в исходнике сайта, в переписке - может дёргать её сколько угодно раз.

На практике встречал сценарий интернет-магазина на WooCommerce, где n8n принимал вебхук о новом заказе и сразу отправлял письмо клиенту и создавал накладную в СДЭК. Без авторизации на вебхуке это значит, что кто угодно может засыпать эндпоинт фиктивными заказами и заставить систему генерировать реальные накладные - лишние расходы на доставку и разгребание отчётности потом.

Разница между n8n Cloud и self-hosted тут ни при чём: URL публичный в обоих случаях, если явно не настроена авторизация в самой Webhook-ноде.

Basic Auth в Webhook-ноде - быстрый вариант для своих скриптов

В настройках Webhook-ноды есть поле Authentication с вариантами None, Basic Auth, Header Auth и, в последних версиях, JWT. Basic Auth - самый простой способ: создаю credential с логином и паролем, n8n сам проверяет заголовок Authorization: Basic и отклоняет запрос без него кодом 403 ещё до того, как сработает остальной сценарий.

Подходит, когда вебхук дёргает код, который я сам пишу и контролирую - например, кастомный скрипт на Tilda, отправляющий данные формы в n8n через fetch, или внутренний сервис на бэкенде. Там логин и пароль просто прописываются в заголовке запроса на стороне отправителя.

Не подходит для вебхуков от внешних провайдеров - Т‑Банка, СДЭК, Telegram Bot API, GitHub. У них нет настройки «добавить Basic Auth заголовок» в личном кабинете: они присылают запрос в своём формате, и подстраиваться приходится вам, а не им.

Секретный токен в заголовке - гибкий вариант для ботов и API

Header Auth в n8n работает иначе: указываю имя заголовка и ожидаемое значение, n8n сравнивает их напрямую, без base64 и логина. Это ровно тот механизм, который нужен для Telegram Bot API - с 2023 года при вызове setWebhook можно передать параметр secret_token, и Telegram будет присылать его в заголовке X‑Telegram-Bot-Api-Secret-Token с каждым обновлением.

Переносил на n8n бота, который раньше был написан на aiogram и работал через polling - там авторизация по сути не требовалась, всё крутилось внутри своего процесса на сервере. При переезде на вебхуки в n8n сразу завёл Header Auth credential с secret_token, чтобы Telegram Trigger нода не реагировала на запросы, которые не от Telegram, - иначе кто-то теоретически мог слать поддельные обновления на тот же URL.

Так же поступаю с интеграциями, где сервис даёт возможность задать произвольный заголовок при настройке колбэка - некоторые платёжные агрегаторы и CRM позволяют это прямо в панели администратора.

Бесплатный материал

🎁 Полезный скрипт в подарок

Подпишитесь на Telegram - пришлю готовый скрипт по этой теме.

Без спама. Отписка в 1 клик.

HMAC-подпись тела запроса - обязательна для денег и логистики

Т‑Банк, СДЭК и большинство платёжных провайдеров не поддерживают ни Basic, ни Header Auth в привычном виде. Вместо этого они подписывают тело запроса общим секретом и кладут результат в отдельное поле - иногда в заголовке, но чаще прямо в JSON-теле. Задача принимающей стороны - пересчитать хеш по тем же правилам и сравнить со значением, которое пришло.

Header Auth в Webhook-ноде тут бесполезен: она сравнивает статичную строку, а подпись каждый раз разная. Поэтому ставлю Webhook-ноду без встроенной авторизации (Authentication: None), обязательно включаю Raw Body в её настройках и сразу за ней - Code-ноду, которая пересчитывает подпись:

const crypto = require('crypto');

const secret = $env.WEBHOOK_SECRET;
const signature = $input.item.json.headers['x-signature'];
const rawBody = $input.item.json.body;

const expected = crypto
  .createHmac('sha256', secret)
  .update(rawBody)
  .digest('hex');

if (expected !== signature) {
  throw new Error('Подпись вебхука не совпадает');
}

return $input.item;

Raw Body здесь критичен: если оставить его выключенным, n8n сам распарсит JSON, а сериализация обратно в строку почти никогда не совпадает байт в байт с тем, что подписывал отправитель - из-за порядка полей, пробелов, экранирования. Полдня однажды потратил на дебаг именно этой мелочи, когда подпись СДЭК не совпадала, хотя секрет был верный.

После Code-ноды ставлю IF-ноду: если подпись не совпала - веду сценарий в Respond to Webhook с кодом 403 и пустым телом, если совпала - дальше по обычной логике. У меня в библиотеке готовых сценариев лежит такой шаблон Code-ноды для проверки подписи - беру его за основу под каждую новую интеграцию с эквайрингом или транспортными службами, чтобы не пересобирать логику с нуля.

Сравнение способов авторизации вебхука в n8n

Способ Где настраивается Что проверяется Когда использовать
Basic Auth Webhook-нода, Credentials Заголовок Authorization с логином и паролем Свои скрипты - Tilda, внутренние сервисы, кастомные формы
Header Auth Webhook-нода, Credentials Произвольный заголовок со статичным значением Telegram Bot API (secret_token), сервисы с настраиваемым заголовком
HMAC-подпись Code-нода после Webhook Хеш от тела запроса, пересчитанный по алгоритму провайдера Платёжные и логистические вебхуки - Т‑Банк, СДЭК, эквайринг
JWT Webhook-нода, Credentials Подпись и срок действия токена Сервисы, которые сами выпускают JWT для колбэков

Частые ошибки при настройке n8n webhook авторизации

  • Оставляют тестовый URL (webhook-test) в продакшен-сценарии - он живёт только пока открыт редактор n8n, а после закрытия вкладки провайдер начинает получать 404 вместо ответа.
  • Хранят секрет прямо в теле workflow как обычный текст в Code-ноде, а не в Credentials или переменных окружения - при экспорте JSON сценария секрет уезжает вместе с файлом.
  • Забывают включить Raw Body при проверке HMAC-подписи - пересчитанный хеш от перепарсенного JSON никогда не совпадёт с оригиналом.
  • Сравнивают токены обычным равенством строк, что нормально для большинства сценариев, но для платежей лучше использовать crypto.timingSafeEqual, чтобы не давать шанс подбору токена по времени ответа.
  • Не логируют отказы авторизации в отдельную ветку сценария - о переборе токена узнают только когда что-то уже сломалось, а не по метрикам.

Связка сервисов без программистов

Автоматизация / n8n

от 25 000 ₽

Подробнее →

Частые вопросы

Нужна ли авторизация вебхука, если сценарий работает только в n8n Cloud?

Да. URL вебхука публичный независимо от хостинга - кто угодно с этой ссылкой может отправить запрос, даже если сам инстанс n8n закрыт паролем от чужих глаз в интерфейсе. Сама ссылка на вебхук по умолчанию не защищена.

Чем Header Auth отличается от Basic Auth в Webhook-ноде n8n?

Basic Auth ожидает заголовок Authorization с логином и паролем в base64 - подходит, когда отправитель поддерживает стандартную HTTP-авторизацию. Header Auth сравнивает значение произвольного заголовка с заданной строкой, что удобнее для сервисов вроде Telegram Bot API, которые сами кладут secret_token в свой заголовок при каждом обновлении.

Можно ли проверить подпись вебхука без написания кода в n8n?

Для простого сравнения статичного токена - да, через Header Auth credential в самой Webhook-ноде. Для HMAC-подписи, где нужно пересчитать хеш от тела запроса и сравнить его со значением из провайдера, без Code-ноды не обойтись: готовой ноды под это в n8n нет.

Что делать, если провайдер присылает подпись в теле запроса, а не в заголовке?

Ставлю Webhook-ноду без встроенной авторизации, включаю Raw Body в её настройках и сразу после неё - Code-ноду, которая достаёт поле подписи из тела, пересчитывает хеш по алгоритму провайдера и через IF-ноду решает, отвечать 200 или обрывать выполнение кодом 403.

При работе с СДЭК, Т‑Банком и похожими интеграциями я обычно сразу закладываю такую проверку в архитектуру сценария, а не добавляю её потом - переписывать готовый рабочий workflow под авторизацию задним числом выходит дороже, чем сделать правильно с первого раза.

Есть задача?

Обсудим в мессенджере

Расскажите, что нужно сделать — отвечу в течение 4 часов в рабочее время. Первая консультация бесплатно.

Самозанятый Калинкин Н. А. · работаю с физлицами и юрлицами

Продолжая пользование настоящим сайтом Вы выражаете своё согласие на обработку Ваших персональных данных (файлов куки) с использованием Yandex.Metrika.
Понятно