deniz.in

Piyasalar

Hava durumu

Hava durumu yükleniyor

· kaynak dev.to (home feed)

Stripe webhook imza doğrulamaları gecikmiş kuyruk yeniden oynatmalarını bozuyor; yeniden imzalayan bir proxy bunu çözüyor

Bir dev.to yazısı, Stripe webhook doğrulamasının beş dakikadan uzun süre tutulan olayları neden reddettiğini, gözle görülür geçici çözümlerin neden güvenli olmadığını ve doğrula-ve-yeniden-imzala yaklaşımıyla çalışan bir proxynin bunu nasıl çözdüğünü açıklıyor.

Stripe webhook imza doğrulamaları gecikmiş kuyruk yeniden oynatmalarını bozuyor; yeniden imzalayan bir proxy bunu çözüyor

Hata modu

Stripe faturalandırma webhook'ları için dayanıklı bir pipeline kurmaya çalışan herkes, dev.to'da yakın tarihli bir yazıda anlatıldığı gibi, er ya da geç aynı duvara çarpar. İşleyiciniz bir customer.subscription.updated olayını işlerken çöker, yük bir dead-letter kuyruğuna düşer, altta yatan hatayı düzeltirsiniz, yeniden oynatmayı tetiklersiniz — ve Stripe SDK'sı, olayın zaman damgasının izin verilen tolerans aralığının dışında kaldığını söyleyen bir hata fırlatır.

Yazıya göre bunun nedeni, Stripe'ın teslimatları imzalama biçiminde yatıyor. Her webhook, bir Unix zaman damgası ile, uç noktanın imzalama gizli anahtarı kullanılarak bu zaman damgasının ham, ayrıştırılmamış JSON gövdesiyle birleştirilmiş dizisi üzerinden hesaplanan HMAC-SHA256 özetini içeren bir Stripe-Signature başlığı taşır. Kodunuz stripe.webhooks.constructEvent() çağırdığında SDK iki bağımsız kontrol yapar: özet gizli anahtarla eşleşmeli ve zaman damgası geçerli zamandan en fazla 300 saniye uzakta olmalıdır. Bu ikinci kontrol salt yeniden oynatma koruması olarak vardır ve kötü niyetli bir yeniden oynatmayı, bir kesintiden sonra meşru bir yeniden teslimattan ayırt edemez. Bir olay kuyrukta beş dakikadan uzun süre kaldığında doğrulama her seferinde başarısız olur.

Güvenliği zayıflatan geçici çözümler

Yazı, ekiplerin genellikle başvurduğu iki düzeltmeyi ve her ikisinin neden tehlikeli olduğunu ele alıyor.

Yeniden denenmiş olaylar için doğrulamayı atlamak — örneğin, yeniden oynatılan istekleri özel bir başlıkla işaretleyip bu başlık varken constructEvent()'i atlamak — uç noktayı URL'yi keşfeden herkese açar. Bu başlığı taşıyan sahte bir abonelik olayı, Stripe'a hiç dokunmadan geçip gider.

SDK'nın tolerans penceresini genişletmek — örneğin üç günlük bir değer geçmek — kuyruktaki olayların geçmesine izin verir, ama bu fiilen tüm faturalandırma yüzeyinde yeniden oynatma korumasını devre dışı bırakır ve bayat ya da araya girilmiş isteklerin geçerli olarak kabul edilmesine olanak tanır.

Kenarda doğrula, içeride yeniden imzala

Yazarın bunun yerine önerdiği mimari, giriş doğrulamasını iç teslimattan ayırır. Uygulamanın önünde küçük bir proxy bulunur ve dört şey yapar:

  1. Her webhook'u Stripe'tan alır ve özgün imzayı 300 saniyelik pencere içinde doğrular, sahte istekleri en baştan reddeder.
  2. Stripe'a anında bir 200 yanıtıyla onay verir; bu, Stripe'ın kendi yeniden deneme döngüsünün zaman aşımına uğramasını engeller.
  3. Dokunulmamış ham yükü ve meta verileri dayanıklı yerel depoya kalıcı olarak yazar — yazı buna örnek olarak WAL modunda SQLite'ı gösteriyor.
  4. İletirken veya yeniden oynatırken — ister milisaniyeler ister günler sonra — olayı aşağı akışa iletmeden önce aynı gizli anahtarla yeni bir zaman damgası ve yeni bir HMAC hesaplar.

Yeniden imzalanan istek, yeni bir teslimattan ayırt edilemeyeceği için uygulama işleyicisi tamamen standart kalır: aynı constructEvent() çağrısı hem ilk teslimatta hem de günler sonraki bir yeniden oynatmada başarılı olur ve uygulamada tek satır kod değişikliği gerekmez.

Sıra dışı olayların ele alınması

Kalan risklerden biri, bayat durumun daha yeni durumu ezmesidir — örneğin bugünkü yeni abonelik oluşturulmasından sonra yeniden oynatılan iki günlük bir abonelik silinmesi. Yazı, her yeniden imzalanan teslimata köken meta verisi eklemeyi öneriyor: bir yeniden oynatma bayrağı, özgün Stripe zaman damgası, teslimat kimliği ve özgün imza başlığı. Aşağı akıştaki kod böylece herhangi bir değişiklik uygulamadan önce özgün zaman damgasını kaydın son güncellenme zamanıyla karşılaştırabilir.

Açık kaynak bir uygulama

Yazar bu deseni HookArmor adıyla paketlemiş: MIT lisanslı, tek bir binary ya da Docker image olarak dağıtılan bir reverse proxy. Yazıya göre olayları yerel SQLite'a tamponluyor, üstel geri çekilmeyle yeniden deniyor, tek tıkla manuel yeniden oynatmaya olanak tanıyan web arayüzlü gömülü bir dead-letter kuyruğu içeriyor ve köken başlıklarını otomatik olarak ekliyor; harici bir veritabanı gerekmiyor.

Neden önemli

Başarısız webhook teslimatlarını daha sonra yeniden denemek üzere tamponlamak standart bir uygulamadır — dead-letter kuyruğunun varlık sebebi tam olarak budur — ancak Stripe'ın beş dakikalık imza penceresi basit yeniden oynatmaları imkânsız kılar ve cazip kısayollar ya doğrulamayı tamamen devre dışı bırakır ya da yeniden oynatma korumasını çürütür. Stripe'ın olayı gerçekten gönderip göndermediği sorusunu, işleyicinizin bunu şu anda işleyip işleyemeyeceği sorusundan ayırmak, her iki güvenlik özelliğini birden korur. Bu desen ayrıca Stripe'ın ötesine geçerek HMAC artı zaman damgasına dayanan her webhook şemasına genellenebilir ve uygulama kodunu kuyruğa özgü özel durumlardan uzak tutar.

  • #stripe
  • #webhooks
  • #security
  • #dead-letter-queue
  • #api

İlgili yazılar