MailLandDocs
Webhook'lar

İ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şenAçıklama
tİmzanın oluşturulduğu andaki Unix zaman damgası (saniye)
v1HMAC-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.

GirdiDeğer
Gizli anahtarwhsec_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:

b9f747ea899eafe911777060ca8f3c90828d37f1e16ee6e9ee98dacf8b316b67

Bu teslimattaki başlık şöyle olurdu:

X-MLND-Signature: t=1708171200,v1=b9f747ea899eafe911777060ca8f3c90828d37f1e16ee6e9ee98dacf8b316b67

Tek 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ÖrnekAçıklama
X-MLND-Signaturet=1708171200,v1=abc123...Zaman damgası ve HMAC-SHA256 imzası
X-MLND-Event-Idevt_a1b2c3d4e5f6...Yinelenen gidermek için benzersiz olay kimliği
X-MLND-Eventmessage.deliveredOlay türü
X-MLND-Event-Version1Veri şeması sürümü
X-MLND-Webhook-Idwh_abc123def456Webhook'unuzun genel kimliği
X-MLND-Attempt1Teslim girişim numarası (1'den başlar)
X-MLND-Delivery-Idp8r2kx7m9wq4rtBu 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-Timestamp1708171200Bu 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ÖrnekNe zaman gönderilir
X-MLND-SourceinboundYalnızca inbound.received teslimatlarında bulunur
X-MLND-Inbound-Email-Idinb_a1b2c3d4e5f6Yalnı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_body

Beklenen 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

verify-signature.sh
#!/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
fi

Yeniden 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:

  1. Yeni bir gizli anahtar almak için POST /v1/webhooks/{id}/regenerate-secret çağrısı yapın
  2. Sunucunuzun doğrulama kodunu yeni gizli anahtarla güncelleyin
  3. 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

Bu sayfada