İmza doğrulama, idempotency anahtarları, replay koruması ve müşteri raporlarını hızlıca hata ayıklama içeren güvenilir webhook entegrasyonlarını öğrenin.

Birisi “webhooklar bozuk” dediğinde genelde üç şeyden birini kasteder: eventler hiç gelmedi, eventler iki kere geldi ya da eventler kafa karıştırıcı bir sırada geldi. Onların bakış açısından sistem bir şeyi “kaçırdı.” Sizin bakış açısından sağlayıcı göndermiştir, ama uç noktanız kabul etmedi, işlemeye çalışırken başarısız oldu ya da beklediğiniz şekilde kaydetmedi.
Webhooklar genel internette yaşar. İstekler gecikebilir, yeniden denenir ve bazen sıra dışı teslim edilir. Çoğu sağlayıcı zaman aşımlarını veya 2xx dışı yanıtları gördüğünde agresifçe yeniden dener. Bu küçük bir aksaklığı (yavaş veritabanı, dağıtım, kısa kesinti) çoğaltmalar ve yarış durumlarına dönüştürebilir.
Kötü loglar bunu rastgele hissettirir. Bir isteğin gerçekten kimden geldiğini kanıtlayamazsanız güvenli şekilde işlem yapamazsınız. Bir müşteri şikayetini belirli bir teslim denemesiyle ilişkilendiremezseniz tahminde bulunursunuz.
Gerçek dünya hatalarının çoğu birkaç kovaya girer:
Pratik hedef basit: gerçek eventleri bir kez kabul etmek, sahte olanları reddetmek ve müşteri raporunu dakikalar içinde hata ayıklayabilmeniz için temiz bir iz bırakmak.
Webhook, sağlayıcının sizin açtığınız uç noktaya gönderdiği bir HTTP isteğidir. Bir API çağrısı gibi çekmezsiniz; gönderici bir şey olduğunda itme yapar ve sizin işiniz onu almak, hızlı cevaplamak ve güvenli şekilde işlemektir.
Tipik bir teslimatta bir istek gövdesi (genelde JSON) ve aldıklarınızı doğrulamanıza ve izlemenize yardımcı başlıklar bulunur. Birçok sağlayıcı zaman damgası, bir event tipi (ör. invoice.paid) ve tekrarları tespit etmek için saklayabileceğiniz benzersiz bir event ID içerir.
Ekipleri şaşırtan kısım: teslimat neredeyse hiç “tam bir kez” değildir. Çoğu sağlayıcı “en az bir kez” hedefler; bu, aynı eventin birden fazla kez, bazen dakikalar ya da saatler arayla gelebileceği anlamına gelir.
Yeniden denemeler sıkıcı nedenlerle olur: sunucunuz yavaştır veya zaman aşımı alır, 500 döndürürsünüz, ağınız 200'ünüzü görmez veya uç noktanız dağıtımlar ya da trafik artışları sırasında kısa süre kullanılamaz hale gelir.
Zaman aşımı özellikle sorunludur. Sunucunuz isteği almış ve işlemeyi bile tamamlamış olabilir, ama yanıt gönderen taraf bu yanıtı zamanında alamaz. Sağlayıcının bakış açısından başarısız oldu, bu yüzden yeniden denerler. Koruma yoksa aynı eventi iki kez işlersiniz.
İyi bir zihinsel model, HTTP isteğini “teslim denemesi” olarak görmek, olay olarak değil. Olay ID ile tanımlanır. İşleminiz sağlayıcı sizi kaç defa çağırdığına değil, o ID'ye dayanmalıdır.
Webhook imzalama, gönderenin isteğin gerçekten onlardan geldiğini ve yol boyunca değiştirilmediğini kanıtlamasının yoludur. İmzalama yoksa, webhook URL'inizi tahmin eden herhangi biri sahte “ödeme başarılı” veya “kullanıcı yükseltildi” eventleri gönderebilir. Daha kötüsü, gerçek bir event transit sırasında (tutar, müşteri IDsi, event tipi) değiştirilebilir ve uygulamanıza yine de geçerli görünebilir.
En yaygın desen, paylaşılan sır ile HMAC'tir. İki taraf da aynı sır değerini bilir. Gönderen tam webhook yükünü (genelde ham istek gövdesi) alır, o sır ile HMAC hesaplar ve imzayı yük ile birlikte gönderir. Sizin işiniz aynı byte'lar üzerinde HMAC'i tekrar hesaplamak ve imzaların eşleşip eşleşmediğini kontrol etmektir.
İmza verileri genelde bir HTTP başlığına konur. Bazı sağlayıcılar zaman damgası da ekler ki replay koruması ekleyebilesiniz. Daha az yaygın olarak, imza JSON gövdesine gömülür; bu risklidir çünkü ayrıştırıcılar veya yeniden seri hale getirme formatı değiştirebilir ve doğrulamayı bozabilir.
İmzaları karşılaştırırken normal bir string eşitlik kontrolü kullanmayın. Basit karşılaştırmalar zamana dayalı fark sızdırabilir ve saldırganın doğru imzayı çok sayıda denemede tahmin etmesine yardımcı olabilir. Dilinizin veya kripto kütüphanenizin sabit zamanlı karşılaştırma fonksiyonunu kullanın ve herhangi bir uyumsuzlukta reddedin.
Bir müşteri “sisteminiz bizim göndermediğimiz bir event kabul etti” raporu verirse, önce imza kontrolleriyle başlayın. İmza doğrulaması başarısızsa muhtemelen sır uyuşmazlığı vardır veya yanlış byte'ları hashliyorsunuzdur (örneğin parse edilmiş JSON yerine ham gövde). Geçerse, gönderen kimliğine güvenebilirsiniz ve deduplaşma, sıra ve yeniden denemelere geçebilirsiniz.
Güvenilir webhook işleme tek bir sıkıcı kuralla başlar: aldığınızı doğrulayın, olmak istediğinizi değil.
Ham istek gövdesini tam olarak geldiği gibi yakalayın. Doğrulamadan önce JSON'u parse edip yeniden seri hale getirmeyin. Ufak farklılıklar (boşluk, anahtar sırası, unicode) byte'ları değiştirir ve geçerli imzaları geçersiz gösterebilir.
Sonra sağlayıcınızın sizin imzalamanızı beklediği tam yükü oluşturun. Birçok sistem timestamp + "." + raw_body gibi bir string imzalar. Zaman damgası süs değil; eski istekleri reddedebilmeniz için oradadır.
Paylaşılan sır ve gereken hash (genelde SHA-256) ile HMAC'i hesaplayın. Sırrı güvenli bir depoda saklayın ve bir parola gibi davranın.
Son olarak, hesapladığınız değeri sabit zamanlı karşılaştırma ile imza başlığı ile karşılaştırın. Eşleşmiyorsa 4xx döndürün ve durun. “Yine de kabul etme.”
Hızlı uygulama kontrol listesi:
Bir müşteri “webhooklar JSON parse middleware ekledikten sonra çalışmayı kesti” diyor. İmza uyumsuzlukları görüyorsunuz, çoğunlukla daha büyük yüklerde. Çözüm genelde doğrulamayı herhangi bir parse işleminden önce ham gövde üzerinde yapmak ve hangi adımın başarısız olduğunu (ör. “imza başlığı eksik” vs “zaman damgası izin verilen pencerenin dışında”) loglamaktır. Bu tek detay hata ayıklama süresini saatlerden dakikalara indirir.
Sağlayıcılar teslimat garantisi vermedikleri için yeniden dener. Sunucunuz bir dakika boyunca kapalı olabilir, bir ağ hop isteği düşürebilir veya handler zaman aşımı olabilir. Sağlayıcı “belki oldu” varsayımıyla aynı eventi yeniden gönderir.
Idempotency anahtarı, zaten işlediğiniz bir olayı tanımanız için kullandığınız makbuz numarasıdır. Bu bir güvenlik özelliği değildir ve imzalama doğrulamasının yerine geçmez. Ayrıca eşzamanlılık altında güvenli şekilde saklanıp kontrol edilmediği sürece yarış koşullarını düzeltmez.
Anahtar seçimi sağlayıcının ne verdiğine bağlıdır. Yeniden denemeler boyunca stabil kalan bir değeri tercih edin:
Webhook aldığınızda önce benzersizlik kuralı kullanarak anahtarı depolayın ki yalnızca bir istek “kazansın.” Sonra olayı işleyin. Aynı anahtarı tekrar görürseniz, işi tekrar yapmadan başarı dönün.
Sakladığınız “makbuzu” küçük ama faydalı tutun: anahtar, işleme durumu (alındı/işlendi/başarısız), zaman damgaları (ilk görüldü/son görüldü) ve minimal bir özet (event tipi ve ilgili nesne IDsi). Birçok ekip anahtarları 7 ila 30 gün saklar, böylece geç gelen yeniden denemeler ve müşteri raporlarının çoğu kapsanır.
Replay koruması basit ama kötü bir problemi durdurur: birisi gerçek bir webhook isteğini (geçerli imza ile) yakalar ve sonra tekrar gönderir. Handler her teslimi yeni kabul ederse, bu replay tekrar edilmiş iade, çoğaltılmış kullanıcı davetleri veya tekrarlanan durum değişiklikleri tetikleyebilir.
Yaygın bir yaklaşım yalnızca yükü değil zaman damgasını da imzalamaktır. Webhook başlıklarında X-Signature ve X-Timestamp gibi başlıklar olabilir. Alındığında imzayı doğrulayın ve zaman damgasının kısa bir pencere içinde taze olduğunu doğrulayın.
Saat sapması genelde yanlış reddin sebebidir. Sunucularınız ve gönderenin sunucuları bir iki dakika fark edebilir ve ağlar teslimatı geciktirebilir. Bir tampon bırakın ve neden reddettiğinizi loglayın.
İyi çalışan pratik kurallar:
abs(now - timestamp) <= window ise (örneğin 5 dakika artı küçük bir esneklik).Zaman damgaları yoksa, yalnızca zaman bazlı gerçek replay koruması yapamazsınız. Bu durumda event ID'leri depolayıp tekrar edenleri reddetmek için idempotency'ye daha fazla yaslanın ve bir sonraki webhook sürümünde zaman damgası zorunlu kılmayı düşünün.
Sır değişimi de önemlidir. İmzalama sırlarını döndürüyorsanız, kısa bir örtüşme döneminde birden fazla aktif sır tutun. Önce en yeni sırla doğrulayın, sonra daha eski olanlara geri dönün. Bu müşteri kesintisini dağıtım sırasında önler. Eğer ekibiniz uç noktaları hızlı dağıtıyorsa (örneğin Koder.ai ile kod üretiyorsanız ve snapshot/rollback kullanıyorsanız), bu örtüşme penceresi eski sürümlerin kısa süreliğine canlı kalması durumunda yardımcı olur.
Yeniden denemeler normaldir. Her teslimin çoğaltılabileceğini, gecikebileceğini veya sıra dışı olabileceğini varsayın. Handler, bir eventi bir kez veya beş kez görmüş gibi aynı davranmalıdır.
İstek yolunu kısa tutun. Olayı kabul etmek için gerekli olanı yapın, sonra daha ağır işleri arka plana alın.
Prodüksiyonda işe yarayan basit bir desen:
2xx'ı yalnızca imzayı doğruladıktan ve eventi kaydettikten (veya kuyrukladığınızdan) sonra döndürün. Eğer 200'ü kaydetmeden önce döndürürseniz, çökme sırasında eventleri kaybedebilirsiniz. Ağır işleri yanıtlamadan önce yaparsanız, zaman aşımı yeniden denemeleri tetikler ve yan etkileri tekrar edebilirsiniz.
Yavaş downstream sistemler yeniden denemelerin acı vermesinin ana nedenidir. E-posta sağlayıcınız, CRM veya veritabanınız yavaşsa, gecikmeyi bir kuyruğun emmesine izin verin. Worker backoff ile yeniden deneyecektir ve sıkışmış işler için uyarı verebilirsiniz, bu da göndereni engellemez.
Sıra dışı eventler de olur. Örneğin, bir subscription.updated subscription.created'dan önce gelebilir. Dayanıklılık için mevcut durumu uygulamadan önce kontrol ederek, upsert kullanarak ve “bulunamadı” durumunu kalıcı başarısızlık yerine daha sonra yeniden denemek için bir sebep olarak değerlendirerek tolerans oluşturun.
Birçok “rastgele” webhook sorunu kendimiz yaratırız. Bunlar kırılgan ağlar gibi görünür, ama tekrar eden desenler halinde ortaya çıkar; genelde bir dağıtım, sır döndürme veya parsing'de küçük bir değişiklik sonrası başlar.
En yaygın imza hatası yanlış byte'ları hash etmektir. JSON'u önce parse ederseniz, sunucunuz yeniden biçimlendirebilir (boşluk, anahtar sırası, sayı biçimi). Sonra imza kontrolü gönderenin imzaladığı gövdenin farklı bir versiyonuna karşı yapılır ve doğrulama başarısız olur. Her zaman tam olarak alındığı byte'lara karşı doğrulayın.
Bir diğer büyük kafa karıştırıcı kaynak sırlar. Ekipler staging'de test eder ama yanlışlıkla production sırrıyla doğrulama yapar veya dönüşten sonra eski sır bırakır. Bir müşteri “yalnızca bir ortamda” hata raporu veriyorsa ilk olarak yanlış sır veya yanlış konfigürasyonu varsayın.
Uzun soruşturmaya yol açan birkaç hata:
Örnek: bir müşteri “order.paid hiç gelmedi” diyor. İmza hataları bir refaktör sonrası başladı; istek parsing middleware'i okuyor ve yeniden encode ediyor, bu nedenle imza kontrolü artık değişmiş bir gövdeyi kullanıyor. Düzeltme basittir, ama buna bakmasını bilmelisiniz.
Bir müşteri “webhook tetiklenmedi” dediğinde bunu tahmin problemi değil, izleme problemi olarak ele alın. Sağlayıcının tek bir teslim denemesini sabitleyin ve bunu sisteminizde takip edin.
Önce sağlayıcının teslim tanımlayıcısını, istek ID'sini veya başarısız denemeye ait event ID'sini alın. Bu tek değerle eşleşen log girdisini hızlıca bulabilmelisiniz.
Oradan üç şeyi sırayla kontrol edin:
Sonra sağlayıcıya ne döndürdüğünüzü onaylayın. Yavaş bir 200, sağlayıcı zaman aşımına uğrarsa 500 kadar kötü olabilir. Durum koduna, yanıt süresine ve handlerınızın ağır işi yapmadan önce onaylayıp onaylamadığına bakın.
Yeniden üretmeniz gerekirse, güvenli yapın: gizlenmiş bir ham istek örneği saklayın (ana başlıklar ve ham gövde) ve aynı sır ve doğrulama kodu ile bir test ortamında yeniden oynatın.
Webhook entegrasyonu “rastgele” hata vermeye başladığında hız mükemmelliyetten önemlidir. Bu çalışma kitabı yaygın nedenleri yakalar.
Önce bir somut örnek alın: sağlayıcı adı, event tipi, yaklaşık zaman damgası (zaman dilimi ile) ve müşterinin görebildiği bir event ID.
Sonra doğrulayın:
Eğer sağlayıcı “20 kez yeniden denedik” diyorsa, önce yaygın desenleri kontrol edin: yanlış sır (imza başarısız), saat sapması (replay penceresi), payload boyutu limitleri (413), zaman aşımı (yanıt yok) ve downstream bağımlılıklardan gelen 5xx patlamaları.
Bir müşteri e-posta atar: “Dün bir invoice.paid eventini kaçırdık. Sistemimiz hiç güncelleme yapmadı.” Hızlıca izlemek için yol:
Önce sağlayıcının teslim etmeye çalışıp çalışmadığını doğrulayın. Event ID, zaman damgası, hedef URL ve uç noktanızın döndürdüğü tam durum kodunu çekin. Eğer yeniden denemeler varsa, ilk başarısızlık nedenini ve daha sonra bir denemenin başarıya ulaşıp ulaşmadığını not edin.
Sonra kenarda kodunuzun ne gördüğünü doğrulayın: o uç nokta için yapılandırılmış imza sırrını doğrulayın, ham istek gövdesiyle imzayı yeniden hesaplayın ve istek zaman damgasını izin verilen pencereye karşı kontrol edin.
Yeniden denemeler sırasında replay pencerelerine dikkat edin. Eğer pencereniz 5 dakika ise ve sağlayıcı 30 dakika sonra yeniden denediyse, meşru bir yeniden denemeyi reddetmiş olabilirsiniz. Eğer bu sizin politikanızsa, kasıtlı ve belgelenmiş olduğundan emin olun. Değilse, pencereyi genişletin veya idempotency'yi birincil savunma yapacak şekilde mantığı değiştirin.
İmza ve zaman damgası iyi görünüyorsa, event ID'yi sisteminizde takip edin ve şu soruları cevaplayın: işlediniz mi, dedupe ettiniz mi yoksa düşürdünüz mü?
Yaygın sonuçlar:
Müşteriye cevap verirken net ve spesifik olun: “10:03 ve 10:33 UTC'de teslim denemelerini aldık. İlk deneme 10s sonra zaman aşımı yaşadı; yeniden deneme bizim 5 dakikalık penceremizin dışındaki zaman damgası nedeniyle reddedildi. Pencereyi genişlettik ve daha hızlı onay ekledik. Gerekirse lütfen X event ID'sini yeniden gönderin.”
Webhook yangınlarını durdurmanın en hızlı yolu her entegrasyonun aynı oyun kitabını takip etmesini sağlamaktır. Gönderenle üzerinde anlaştığınız sözleşmeyi yazın: gerekli başlıklar, tam imzalama yöntemi, hangi zaman damgasının kullanıldığı ve hangi ID'leri benzersiz saydığınız.
Sonra her teslim denemesi için ne kaydedeceğinizi standardize edin. Küçük bir fiş kaydı genelde yeterlidir: received_at, event_id, delivery_id, signature_valid, idempotency_result (yeni/çoğaltma), handler_version ve response status.
Büyüdükçe işe yarayan bir iş akışı:
Koder.ai (koder.ai) üzerinde uygulamalar kuruyorsanız, Planning Mode webhook sözleşmesini (başlıklar, imzalama, IDler, yeniden deneme davranışı) önce tanımlamak ve ardından tutarlı bir uç nokta ve fiş kaydı üretmek için güzel bir yoldur. Bu tutarlılık, hata ayıklamayı kahramanca değil hızlı kılar.
Çünkü webhook teslimi genellikle en az bir kez (at-least-once) şeklindedir, tam bir kez (exactly-once) değildir. Sağlayıcılar zaman aşımı, 5xx yanıtları ve bazen 2xx yanıtınızı zamanında göremediklerinde yeniden denerler; bu nedenle tekrarlar, gecikmeler ve sıra dışı teslimatlar olabilir, her şey “çalışıyor” olsa bile.
Varsayılan kural şu olsun: önce imzayı doğrulayın, sonra olayı kaydedip/dedupe edin, sonra 2xx ile yanıt verin, ardından ağır işleri asenkron yapın.
Ağır işleri cevap vermeden önce yaparsanız zaman aşımı yaşarsınız ve yeniden denemelere neden olursunuz; cevap verip hiçbir şey kaydetmezseniz çökme durumunda olayları kaybedebilirsiniz.
Tam olarak alınan ham istek gövdesini kullanın. Doğrulamadan önce JSON'u parse edip yeniden seri hale getirmeyin—boşluklar, anahtar sırası ve sayı biçimlendirmesi imzaları bozabilir.
Ayrıca sağlayıcının imzaladığı yükü (timestamp + "." + raw_body gibi) tam olarak yeniden oluşturduğunuzdan emin olun.
Bir 4xx dönün (genelde 400 veya 401) ve yükü işlemeyin.
Eksik imza başlığı, uyumsuzluk veya zaman damgası penceresi gibi kısa bir neden kaydedin, fakat sırlar veya tam hassas yükleri loglamayın.
Idempotency anahtarı, yeniden denemelerin yan etkileri tekrar uygulamasını önlemek için sakladığınız kararlı, benzersiz bir tanımlayıcıdır. Bu bir güvenlik özelliği değildir ve imzalama doğrulamasının yerine geçmez. Ayrıca eşzamanlılık altında güvenli saklama ve kontrol gerektirir.
En iyi seçenekler:
Yan etkilerden önce idempotency anahtarını önce saklayın; benzersizlik kuralı uygulayın. Sonra ya:
Eğer insert benzersizlik hatası verirse, 2xx döndürün ve iş mantığını atlayın.
İmzalanan veriye bir de zaman damgası ekleyin ve kısa bir pencere dışında kalan istekleri reddedin (örneğin birkaç dakika).
Meşru yeniden denemeleri engellememek için:
Teslim sırasının olay sırasına eşit olduğunu varsaymayın. İşleyicileri toleranslı yapın:
Olay ID'si ve tipini saklayın ki sıra garip olsa bile ne olduğunu çözebilesiniz.
Her teslim denemesi için küçük bir “fiş” loglayın ki bir olayı uçtan uca izleyebilesiniz:
Logları event ID ile aranabilir tutun ki destek hızlıca müşteri raporlarına cevap verebilsin.
Tek bir somut tanımlayıcı isteyin: event ID veya delivery ID ve yaklaşık zaman damgası.
Sonra şu sırayı kontrol edin:
Koder.ai ile uç noktalar oluşturuyorsanız, handler desenini (verify → record/dedupe → queue → respond) projeler arasında tutarlı kullanın; tutarlılık, olaylar olduğunda bu kontrolleri hızlandırır.
Eşzamanlılık altında yalnızca bir isteğin “kazandığından” emin olmak için benzersizlik kuralı uygulayın.