Webhook'lar

Kripto ödeme webhook'ları nasıl güvenli hale getirilir

Bir ödeme webhook uç noktasını ne korur: webhook imzasını doğrulamak, idempotent işleme, kesin durum kodları, yeniden denemeler ve günlükleme. Qvard webhook'larının gerçekte nasıl çalıştığına dayanır.

Webhook, mağazanızın bir siparişin ödendiğine karar verdiği andır. O uç noktayı doğru gövdeyle çağırabilen biri bedava mal almayı deneyebilir; bu yüzden çoğu rotadan daha fazla özen hak eder. Bu rehber, Qvard webhook'larının bugün gerçekte nasıl çalıştığına dayanarak bir ödeme webhook'unu neyin koruduğunu anlatıyor; X-Qvard-Signature başlığı da dahil; bu başlık bir bildirimin Qvard'dan geldiğini doğrulamanızı sağlar.

Qvard webhook'u nedir, ne değildir

Bir ödeme tamamlandığında Qvard, projenizde kayıtlı callback URL'ye bir POST isteği gönderir. Gövde küçüktür: ödemeyi oluştururken verdiğiniz id ve ödemenin status değeri. Webhook, ödeme tamamlandığında gönderilir; bu, siparişi ödendi işaretlemenin sinyalidir.

İstek, t=<unix>,v1=<hex> biçiminde bir X-Qvard-Signature başlığı taşır: zaman damgası ve ham gövdenin gizli anahtarınızla hesaplanmış HMAC-SHA256 değeri. Anahtar döndürmeden sonraki 24 saat boyunca iki v1 değeri gönderilir ve ikisinden biri geçerlidir. Eski anahtarı olan (qvard_sk_ öneki olmayan) işletmelere webhook'ta ayrıca x-api-key başlığı da gelir; yine de imzayı doğrulayın. Doğrulamayı ham gövde üzerinden, JSON ayrıştırılmadan önce yapın; bu rehber Qvard'ın bugün gönderdiği imzayı anlatır.

Tasarımın iki özelliği geri kalan her şeyi belirler: uç noktanız herkese açık bir URL'dir ve onu koruyan tek sır, imzayı doğrulamakta kullandığınız gizli anahtarınızdır.

Gerçekten önemli tehditler

Kısa bir liste uzun bir listeden daha yararlıdır:

  • Sahte istek. Uç noktanızı bulan biri, bir sipariş ödendi işaretlensin diye { "id": "1234", "status": "completed" } gönderir. Bunu imza kontrolü durdurur.
  • Sızan anahtar. Aynı gizli anahtar webhook'u imzalar ve API çağrılarınızı doğrular. Bir depoda, günlükte veya ön yüz kodunda görünürse ikisi de açıkta kalır.
  • Tekrarlanan teslimat. Saldırı değildir ama gerçek zararın en yaygın nedenidir: aynı olay iki kez gelir ve sipariş iki kez yerine getirilir.
  • Yavaş veya hata veren uç nokta. Kaçan teslimatlar ödenmiş siparişleri yerine getirilmemiş bırakır.
  • Özensiz günlükleme. İsteğin tamamını günlüğe yazmak anahtarı günlük dosyalarınıza koyar.

Sonraki bölümlerin her biri bu tehditlerden birini kapatır.

Anahtarı kontrol edin ve güvenle karşılaştırın

Her istekte X-Qvard-Signature başlığını okuyun ve başka bir şey yapmadan önce ham gövde üzerinden doğrulayın. İki ayrıntı önemlidir:

  • Sabit zamanlı karşılaştırma. Düz bir ===, baştaki kaç karakterin eşleştiği hakkında bilgi sızdırabilir. Dilinizin sabit zamanlı işlevini kullanın (Node.js'te crypto.timingSafeEqual, PHP'de hash_equals, Python'da hmac.compare_digest). İşlev eşit boyut gerektiriyorsa önce uzunlukları kontrol edin.
  • Sessizce reddedin. Açıklama yapmadan 400 yanıtlayın. İmzanın eksik mi yanlış mı olduğunu söylemeyin.

Aşağıdaki örnek işleyicinin tamamını gösterir: imza kontrolü, küçük bir gövde sınırı, alanların doğrulanması, yalnızca henüz ödenmemiş bir siparişi değiştiren bir güncelleme ve tam olarak 200 yanıtı. Anahtarı bir ortam değişkeninde veya sır yöneticisinde tutun; asla depoda veya ön yüz kodunda değil.

Node.jswebhook.js
import express from 'express';
import { Qvard } from '@qvard/node';

const secret = process.env.QVARD_SECRET_KEY;
const qvard = new Qvard(secret);
const app = express();

app.post('/webhooks/qvard', express.raw({ type: 'application/json', limit: '10kb' }), async (req, res) => {
  let event;
  try {
    event = qvard.webhooks.constructEvent(req.body, req.get('X-Qvard-Signature'), secret);
  } catch {
    return res.sendStatus(400);
  }

  const { id, status } = event;
  if (typeof id !== 'string' || status !== 'completed') return res.sendStatus(200);

  // Idempotent: the update only matches an order that is not paid yet.
  const changed = await db.orders.markPaidIfNot(id);
  if (changed) queue.push({ type: 'fulfil', orderId: id }); // slow work happens after the answer

  return res.sendStatus(200); // exactly 200
});

İşleyiciyi idempotent yapın

Qvard, bir teslimatı yalnızca uç noktanız tam olarak HTTP 200 yanıtladığında başarılı sayar. Başka herhangi bir durum, zaman aşımı veya yönlendirme hata sayılır ve yeniden denenir: yaklaşık altı dakikada toplam beş deneme. Sonuç olarak işleyiciniz bazen aynı olayı birden fazla kez görecektir; örneğin sunucunuz işi yaptı ama yanıt kayboldu.

Buna göre tasarlayın:

  • Durum değişikliğini koşullu yapın: «bu siparişi henüz ödenmemişse ödendi işaretle», ideal olarak tek bir veritabanı ifadesiyle, böylece iki paralel teslimat birlikte kazanamaz.
  • Yerine getirmeyi (e-postalar, anahtarlar, erişim) yalnızca güncelleme gerçekten bir satırı değiştirdiyse başlatın.
  • Tanımadığınız siparişlerin olaylarını yok sayın ama yine de 200 yanıtlayın; aksi halde Qvard hiç işlemeyeceğiniz bir şeyi yeniden denemeye devam eder.
  • Yalnızca completed durumunda hareket edin. Başka hiçbir durum siparişi ödendi işaretlememelidir.

Bu aynı zamanda yeniden oynatılan isteğe karşı savunmadır: tekrarlanan geçerli bir olay ikinci seferde hiçbir şeyi değiştirmez.

Hızlı yanıtlayın, işi sonra yapın

Uç noktanız Qvard vazgeçmeden yanıt vermelidir; bu yüzden kısa tutun: kontrol et, güncelle, kuyruğa at, yanıtla. E-posta göndermek, başka sistemleri çağırmak ve dosya üretmek gibi yavaş kısımları yanıttan sonra bir kuyruktan yapın.

Uç noktanızın bilmediği şeyi de düşünün. Gövde yalnızca id ve status taşır; bu yüzden beklenen tutar webhook'tan değil, kendi siparişinizden gelir. İstek gövdesinden asla tutar, para birimi veya ürün almayın.

Uç noktayı yalnızca HTTPS üzerinden sunun ve önünde proxy veya yönlendirme olmadığından emin olun: yönlendirmeler takip edilmez, bu yüzden http'den https'ye bir 301 başarısız bir teslimattır.

Günlükler, izleme ve kurtarma

Webhook'ları para hareketi gibi ele alın ve iz bırakın.

  • Sırrı değil, kararınızı günlüğe yazın. id, status, zaman ve kararınızı (uygulandı, yinelenen, bilinmeyen sipariş, anahtar reddedildi) saklayın. Gizli anahtarınızı asla günlüğe yazmayın.
  • Ret durumlarında uyarı kurun. Ani bir 400 yanıt serisi, birinin uç noktayı yokladığı ya da anahtarınızı bir yerde değiştirip her yerde değiştirmediğiniz anlamına gelir.
  • Mutabakat yapın. Günde bir kez, ödenmiş saydığınız siparişleri Qvard panelindeki bakiyeniz ve ödemelerle karşılaştırın.
  • Kurtarın. Sunucunuz yeniden deneme penceresinden uzun süre kapalı kaldıysa o ödemenin bildirimini panelden yeniden gönderin; idempotent işleyiciniz halleder.

Anahtarın sızdığından şüpheleniyorsanız değiştirin ve hangi sistemlerinizin onu kullandığını gözden geçirin.

Yayına almadan önce kontrol listesi

  • Uç nokta HTTPS, herkese açık ve ağınızın dışından erişilebilir.
  • X-Qvard-Signature ham gövde üzerinden doğrulanır, aksi halde 400 döner.
  • Gövde boyutu sınırlanır, id ve status doğrulanır.
  • Sipariş yalnızca completed durumunda ve yalnızca henüz ödenmemişse ödendi işaretlenir.
  • Tam olarak 200 hızla yanıtlanır, yavaş iş sonra yapılır.
  • Gövdedeki tutarlara veya ürünlere asla güvenilmez.
  • Anahtar asla günlüğe yazılmaz.
  • Başarısız bir yanıtı, yinelenen bir teslimatı ve bilinmeyen bir siparişi test ettiniz.

Webhook çevresindeki tam akış için bir web sitesinde kripto ödemesi nasıl kabul edilir yazısına bakın. İstek ve yanıt biçimleri geliştirici belgelerinde.

FAQ

Qvard webhook'ları HMAC ile imzalıyor mu?

Evet. Her webhook, t=<unix>,v1=<hex> biçiminde bir X-Qvard-Signature başlığı taşır: zaman damgası ve ham gövdenin gizli anahtarınızla hesaplanmış HMAC-SHA256 değeri. Ham gövde üzerinden sabit zamanlı olarak doğrulayın ve gizli anahtarınızı sır olarak saklayın.

Uç noktam hangi durum kodunu döndürmeli?

Tam olarak 200. Başka herhangi bir durum, zaman aşımı veya yönlendirme başarısız teslimat sayılır ve yeniden denenir; yaklaşık altı dakikada toplam beş deneme.

Ödeme tamamlandığında sunucum kapalıysa?

Yeniden denemeler yaklaşık altı dakikayı kapsar. Sonrasında ödemenin bildirimini panelden yeniden gönderin. İdempotent bir işleyici bunu güvenli kılar.

Webhook'taki tutara güvenebilir miyim?

Webhook yalnızca ödeme kimliğini ve durumunu taşır. Tutarı kendi siparişinizden alın ve yalnızca completed durumunda ödendi işaretleyin.

İlgili makaleler

İlgili makaleler