İmza Doğrulama
Gelen webhook verilerinin özgünlüğünü sağlamak için webhook imzalarını doğrulayın
Her webhook teslimi, isteğin MailLand'den geldiğini ve aktarım sırasında değiştirilmediğini doğrulayabilmeniz için bir şifreleme imzası içerir. Üretim ortamında her zaman imzaları doğrulayın.
İmzalama Nasıl Çalışır
MailLand, her webhook verisini webhook'unuzun gizli anahtarını kullanarak HMAC-SHA256 ile imzalar. İmza X-MLND-Signature başlığına eklenir.
İmza biçimi:
X-MLND-Signature: t=1708171200,v1=b9f747ea899eafe911777060ca8f3c90828d37f1e16ee6e9ee98dacf8b316b67| Bileşen | Açıklama |
|---|---|
t | İmzanın oluşturulduğu andaki Unix zaman damgası (saniye) |
v1 | HMAC-SHA256 onaltılık imza (küçük harf) |
İmzalanan veri:
{timestamp}.{raw_json_body}İmza, zaman damgasının bir nokta ve ham JSON istek gövdesiyle birleştirilmesiyle hesaplanır.
Çalışılmış Örnek
Canlıya geçmeden önce uygulamanızı tam olarak bu değerlerle karşılaştırın. Aşağıdaki her şey gerçektir: imza, MailLand’in bu gizli anahtar, zaman damgası ve gövde için ürettiği imzadır.
| Girdi | Değer |
|---|---|
| Gizli anahtar | whsec_docs_example_secret_do_not_use |
Zaman damgası (t) | 1708171200 |
| Ham gövde | {"event":"message.delivered","event_id":"evt_a1b2c3d4e5f6"} |
İmzalanan dize: zaman damgası, bir nokta, sonra gövdenin aynısı:
1708171200.{"event":"message.delivered","event_id":"evt_a1b2c3d4e5f6"}Bu dizenin gizli anahtarla üretilmiş HMAC-SHA256 değeri, küçük harfli onaltılık:
b9f747ea899eafe911777060ca8f3c90828d37f1e16ee6e9ee98dacf8b316b67Bu teslimattaki başlık şöyle olurdu:
X-MLND-Signature: t=1708171200,v1=b9f747ea899eafe911777060ca8f3c90828d37f1e16ee6e9ee98dacf8b316b67Tek satırda yeniden üretin:
printf '%s' '1708171200.{"event":"message.delivered","event_id":"evt_a1b2c3d4e5f6"}' \
| openssl dgst -sha256 -hmac 'whsec_docs_example_secret_do_not_use'Bu örneğin zaman damgası geçmişte kaldığı için gerçek bir doğrulayıcı onu tolerans kontrolünde reddeder. Önce zaman kontrolünü kapatıp HMAC’i test edin, sonra yeniden açın.
Gönderilen Başlıklar
Her webhook teslimi şu başlıkları içerir:
| Başlık | Örnek | Açıklama |
|---|---|---|
X-MLND-Signature | t=1708171200,v1=abc123... | Zaman damgası ve HMAC-SHA256 imzası |
X-MLND-Event-Id | evt_a1b2c3d4e5f6... | Yinelenen gidermek için benzersiz olay kimliği |
X-MLND-Event | message.delivered | Olay türü |
X-MLND-Event-Version | 1 | Veri şeması sürümü |
X-MLND-Webhook-Id | wh_abc123def456 | Webhook'unuzun genel kimliği |
X-MLND-Attempt | 1 | Teslim girişim numarası (1'den başlar) |
X-MLND-Delivery-Id | p8r2kx7m9wq4rt | Bu denemenin kimliği, her yeniden denemede yeni; teslimat geçmişindeki publicId. Tekilleştirme için değildir: bkz. Sürümleme |
X-MLND-Delivery-Timestamp | 1708171200 | Bu denemenin gönderildiği an (Unix saniyesi); imzadaki t ile her zaman aynı |
Hangi olaya abone olduğunuza bağlı iki başlık daha vardır:
| Başlık | Örnek | Ne zaman gönderilir |
|---|---|---|
X-MLND-Source | inbound | Yalnızca inbound.received teslimatlarında bulunur |
X-MLND-Inbound-Email-Id | inb_a1b2c3d4e5f6 | Yalnızca inbound.received teslimatlarında bulunur |
X-MLND-Message-Id şu anda message.* teslimatlarında gönderilmiyor. Bunun yerine olay yükündeki data.message_id alanını kullanın.
Doğrulama Adımları
Zaman damgasını ve imzayı çıkarın
X-MLND-Signature başlığını ayrıştırın. t=... ve v1=... bileşenlerini elde etmek için , ile bölün.
İmzalanan veriyi hazırlayın
Zaman damgasını, bir nokta (.) ve ham istek gövdesini birleştirin:
signed_payload = timestamp + "." + raw_bodyBeklenen imzayı hesaplayın
Webhook gizli anahtarınızı anahtar, imzalanan veriyi mesaj olarak kullanarak HMAC-SHA256 hash'i oluşturun. Küçük harfli onaltılığa dönüştürün.
İmzaları karşılaştırın
Hesaplanan imzanın başlıktaki v1 değeriyle eşleşip eşleşmediğini kontrol etmek için sabit zamanlı karşılaştırma kullanın.
Zaman damgasını doğrulayın
Yeniden oynatma saldırılarını önlemek için zaman damgasının geçerli zamandan 5 dakika içinde olduğunu kontrol edin.
Kod Örnekleri
#!/usr/bin/env bash
# Compute and verify an HMAC-SHA256 webhook signature using openssl
SIGNATURE_HEADER="t=1708171200,v1=b9f747ea899eafe911777060ca8f3c90828d37f1e16ee6e9ee98dacf8b316b67"
RAW_BODY='{"event":"message.delivered","event_id":"evt_a1b2c3d4e5f6"}'
SECRET="whsec_docs_example_secret_do_not_use"
TOLERANCE=300
# Parse timestamp and signature from header
TIMESTAMP=$(echo "$SIGNATURE_HEADER" | grep -oP '(?<=t=)[^,]+')
RECEIVED_SIG=$(echo "$SIGNATURE_HEADER" | grep -oP '(?<=v1=).+')
# Check timestamp tolerance
NOW=$(date +%s)
DIFF=$(( NOW - TIMESTAMP ))
if [ "${DIFF#-}" -gt "$TOLERANCE" ]; then
echo "Error: Timestamp outside tolerance window" >&2
exit 1
fi
# Compute expected signature
SIGNED_PAYLOAD="${TIMESTAMP}.${RAW_BODY}"
EXPECTED=$(printf '%s' "$SIGNED_PAYLOAD" | openssl dgst -sha256 -hmac "$SECRET" | awk '{print $2}')
# Compare signatures
if [ "$EXPECTED" = "$RECEIVED_SIG" ]; then
echo "Signature valid"
else
echo "Signature invalid" >&2
exit 1
fiYeniden Oynatma Saldırısı Önleme
İmza başlığındaki zaman damgası, yeniden oynatma saldırılarını önler. Bir saldırgan geçerli bir webhook teslimatını yakalayıp daha sonra yeniden gönderirse, zaman damgası kontrolü bunu reddeder.
MailLand'in varsayılan toleransı 5 dakika (300 saniye)'dir. Bunu doğrulama kodunuzda ayarlayabilirsiniz, ancak anlamlı yeniden oynatma saldırılarını önlemek için yeterince kısa tutun.
Ayrıca her olayın X-MLND-Event-Id başlığında benzersiz bir event_id değeri bulunur. Ek koruma için işlenmiş olay kimliklerini saklayın ve kopyaları reddedin.
MailLand kendi tarafında gönderim niyetini tekilleştirir: iki kez üretilen bir olay, 24 saatlik pencerede webhook başına yalnızca bir kez sevk edilir. Bu "en fazla bir kez teslim edilir" demek değildir: başarısız bir teslimat yeniden denenir ve her deneme aynı event_id ve aynı gövdeyi taşır; yalnızca X-MLND-Attempt ve imza zaman damgası değişir. event_id üzerinden tekilleştirin ve tekrarlanan teslimatları beklenen durum sayın.
Her Teslimat İmzalıdır
İmzasız bir teslimat yolu yoktur. Bir webhook'un kullanılabilir bir imzalama gizli anahtarı yoksa,
MailLand veriyi X-MLND-Signature başlığı olmadan göndermek yerine teslimatı başarısız kılar ve bu
hatayı kaydeder: bu yüzden eksik bir imza başlığı, doğrulayıcınızın hiçbir zaman göz ardı etmesi
gereken bir şey değildir. Bu başlığı taşımayan her isteği reddedin.
Gizli Anahtarları Yeniden Oluşturma
Webhook gizli anahtarınızın ele geçirildiğinden şüpheleniyorsanız:
- Yeni bir gizli anahtar almak için
POST /v1/webhooks/{id}/regenerate-secretçağrısı yapın - Sunucunuzun doğrulama kodunu yeni gizli anahtarla güncelleyin
- Eski gizli anahtar hemen geçersiz kılınır
Gizli anahtarları yeniden oluştururken tolerans süresi yoktur. Geçerli olayların reddedilmesini önlemek için doğrulama kodunuzu bir sonraki webhook teslimatından önce güncelleyin.
Yaygın Hatalar
- Doğrulamadan önce gövdeyi JSON olarak ayrıştırma: imza ham baytlar üzerinden hesaplanır, yeniden seri hale getirilmiş bir JSON nesnesi üzerinden değil. Önce doğrulayın, sonra ayrıştırın.
- Sabit zamanlı yerine dize karşılaştırması kullanma: normal dize karşılaştırması zamanlama saldırılarına karşı savunmasızdır.
- Zaman damgasını yok sayma: zaman damgası doğrulaması olmadan, yakalanan veriler süresiz olarak yeniden oynatılabilir.
- Gizli anahtarı sabit kodlama: ortam değişkenleri veya gizli anahtar yöneticisi kullanın.
Sonraki Adımlar
- Yeniden Deneme Mantığı: yeniden deneme davranışını ve hata yönetimini anlayın
- Olaylar: tam olay türü başvurusu
- Webhook'lara Genel Bakış: webhook'ları oluşturun ve yönetin