Перейти к документации
Go

Проверка вебхуков

Проверьте подпись доставки, прежде чем доверять её содержимому.

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

webhook.go
package main import (	"io"	"log"	"net/http"	"os" 	"github.com/bfzli/openemail-go") func main() {	secret := os.Getenv("OPENEMAIL_WEBHOOK_SECRET") 	http.HandleFunc("/webhooks/openemail", func(writer http.ResponseWriter, request *http.Request) {		payload, err := io.ReadAll(http.MaxBytesReader(writer, request.Body, 1<<20))		if err != nil {			writer.WriteHeader(http.StatusBadRequest) 			return		} 		event, err := openemail.VerifyWebhookSignature(payload, request.Header, secret)		if err != nil {			writer.WriteHeader(http.StatusBadRequest) 			return		} 		log.Println(event.String("type"), event.ID())		writer.WriteHeader(http.StatusNoContent)	}) 	log.Fatal(http.ListenAndServe(":8080", nil))}

openemail.VerifyWebhookSignature читает заголовок X-OpenEmail-Signature, проверяет его HMAC по метке времени и телу за постоянное время и возвращает событие как openemail.Object. Секрет тот самый, который вернул client.Webhooks.Create.

Передавайте необработанное тело в точности таким, каким оно пришло. Тело, которое разобрали и закодировали заново, уже не совпадает со своей подписью.

Старые доставки

tolerance.go
payload := []byte(`{"id":"evt_1","type":"email.received"}`)headers := http.Header{"X-OpenEmail-Signature": {"t=1767225600,v1=5f2d"}} _, err := openemail.VerifyWebhookSignature(payload, headers, "whsec_example", openemail.WithTolerance(time.Minute)) if errors.Is(err, openemail.ErrWebhookSignature) {	fmt.Println("refused:", err)}

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

  • Отсутствующий или неверно составленный заголовок, несовпадающая подпись и слишком старая доставка возвращают ошибку, которая совпадает с openemail.ErrWebhookSignature.
  • После смены секрета доставка может нести больше одной подписи, и достаточно совпадения любой из них.
  • Отвечайте статусом 2xx быстро. Доставка, получившая любой другой ответ, повторяется позже.