Зачем проверять веб-хуки?
Без проверки любой, кто обнаружит URL вашего веб-хука, может отправить поддельные запросы на вашу конечную точку, потенциально вызвав:- Манипуляцию данными: вредоносные акторы могли бы запустить действия на основе поддельных событий
- Нарушения безопасности: поддельные сообщения могли бы внедрить вредоносные данные в ваши системы
- Истощение ресурсов: злоумышленники могли бы наводнить вашу конечную точку поддельными запросами
Получение вашего секрета подписания
Каждая конечная точка веб-хука имеет уникальный секрет подписания, который вы будете использовать для проверки запросов. Вы можете найти этот секрет в консоли AgentInbox при создании вашего веб-хука или путем получения деталей вашего веб-хука:from agentinbox import AgentInbox
client = AgentInbox()
# Get webhook details including the signing secret
webhook = client.webhooks.get(webhook_id="ep_xxx")
# The secret starts with "whsec_"
signing_secret = webhook.secret
print(f"Signing secret: {signing_secret}")
Сохраняйте свой секрет подписания безопасно в переменных окружения. Никогда не фиксируйте его в управление версиями и не раскрывайте в коде на стороне клиента.
Заголовки проверки
Каждый запрос веб-хука от AgentInbox включает три заголовка, используемые для проверки:| Заголовок | Описание |
|---|---|
svix-id | Уникальный идентификатор сообщения. Тот же ID используется для повторных попыток одного и того же сообщения. |
svix-timestamp | Unix отметка времени (секунды) отправки сообщения. |
svix-signature | Разделенный пробелом список подписей в формате v1,<base64> (например, v1,abc123 v1,def456). |
Проверка с помощью библиотеки Svix (рекомендуется)
Самый простой способ проверить веб-хуки — использовать официальную библиотеку Svix, которая обрабатывает все криптографические детали для вас.import os
from dotenv import load_dotenv
from flask import Flask, request
from svix.webhooks import Webhook, WebhookVerificationError
load_dotenv()
app = Flask(__name__)
secret = os.environ["AGENTINBOX_WEBHOOK_SECRET"]
@app.route('/webhooks', methods=['POST'])
def webhook_handler():
headers = request.headers
payload = request.get_data()
try:
wh = Webhook(secret)
msg = wh.verify(payload, headers)
except WebhookVerificationError as e:
return ('', 400)
# Do something with the message...
return ('', 204)
if name == '__main__':
app.run(port=3000)
Проверка подписи требует точного тела запроса. Если вы используете middleware для разбора тела (как
express.json()), убедитесь, что вы захватили сырое тело перед разбором, или используйте express.raw() для вашей конечной точки веб-хука.Тестирование локально с ngrok
Во время разработки вам потребуется способ для AgentInbox достичь вашего локального сервера. ngrok создает открытый URL, который туннелирует на вашу локальную машину.Шаг 1: сохраните сервер веб-хука
Создайте файл сервера веб-хука:import os
from dotenv import load_dotenv
from flask import Flask, request
from svix.webhooks import Webhook, WebhookVerificationError
load_dotenv()
app = Flask(__name__)
secret = os.environ.get("AGENTINBOX_WEBHOOK_SECRET")
@app.route('/webhooks', methods=['POST'])
def webhook_handler():
headers = request.headers
payload = request.get_data()
try:
wh = Webhook(secret)
msg = wh.verify(payload, headers)
print(f"Received event: {msg}")
except WebhookVerificationError as e:
print(f"Verification failed: {e}")
return ('', 400)
# Do something with the message...
return ('', 204)
if name == '__main__':
app.run(port=3000)
Шаг 2: установите зависимости и запустите сервер
pip install flask python-dotenv svix
python webhook_server.py
Вы должны увидеть результат похожий на:
* Serving Flask app 'webhook_server'
* Debug mode: off
* Running on http://127.0.0.1:3000
Press CTRL+C to quit
Шаг 3: запустите ngrok
В новом окне терминала запустите ngrok, чтобы создать открытый туннель на ваш локальный сервер:https:// (например, https://da550b82a183.ngrok.app).
Шаг 4: добавьте URL в консоль AgentInbox
- Перейдите на консоль AgentInbox
- Перейдите на Webhooks на боковой панели
- Нажмите Create Webhook (или отредактируйте существующий)
- Вставьте URL ngrok с путем
/webhooks:https://da550b82a183.ngrok.app/webhooks - Выберите события, которые вы хотите получать
- Сохраните веб-хук
- Скопируйте секрет подписания и добавьте его в файл
.env:
Шаг 5: запустите тестовое событие
Отправьте письмо на один из входящих ящиков AgentInbox или используйте консоль для отправки тестового события. Вы должны увидеть веб-хук, полученный в терминале:ngrok отлично подходит для локальной разработки, но для производства вам потребуется развернуть сервер веб-хука на хостинг-провайдер. Смотрите следующий раздел для вариантов развертывания.
Развертывание в производстве
Для производства вам потребуется развернуть сервер веб-хука на хостинг-провайдер, который дает вам стабильный открытый HTTPS URL. Мы рекомендуем Render за его простоту и щедрый бесплатный уровень.Лучшие практики
Всегда проверяйте в производстве
Всегда проверяйте в производстве
Хотя вы можете пропустить проверку при локальной разработке, всегда включайте ее в производственных средах. Скомпрометированная конечная точка веб-хука может быть серьезной уязвимостью безопасности.
Используйте переменные окружения
Используйте переменные окружения
Никогда не кодируйте вашу секретную подпись жестко. Используйте переменные окружения или менеджер секретов:
Решение проблем
Проверка подписи не удалась
Проверка подписи не удалась
- Убедитесь, что вы используете сырое тело запроса, а не разобранную/измененную версию
- Проверьте, что ваш секрет подписания правильный и соответствует конечной точке веб-хука
- Убедитесь, что вы правильно извлекаете заголовки (они чувствительны к регистру?)
- Убедитесь, что отметка времени не истекла (допуск по умолчанию составляет 5 минут)
Отсутствующие заголовки
Отсутствующие заголовки
Если заголовки отсутствуют, убедитесь, что ваш сервер/фреймворк их не удаляет. Некоторые обратные прокси могут потребовать конфигурации для передачи пользовательских заголовков.
Проблемы разбора тела
Проблемы разбора тела
Если вы используете middleware для разбора тела, убедитесь, что вы обращаетесь к сырому телу для проверки. В Express используйте
express.raw() для вашего маршрута веб-хука.