JekCMS Webhook Güvenliği: İmzalama ve Doğrulama

Webhook endpointlerinizi HMAC-SHA256 imzalama ile güvence altına alma rehberi: JekCMS'in yerleşik imza kontrolü nasıl çalışır, hash_equals neden önemlidir ve isterseniz tekrar koruması, IP izin listesi gibi ek sertleştirmeleri nasıl kendiniz eklersiniz.

JekCMS Webhook Güvenliği: İmzalama ve Doğrulama

Webhook endpointlerinizi HMAC-SHA256 imzalama ile güvence altına alma rehberi: JekCMS'in yerleşik imza kontrolü nasıl çalışır, hash_equals neden önemlidir ve isterseniz tekrar koruması, IP izin listesi gibi ek sertleştirmeleri nasıl kendiniz eklersiniz.

Webhook'lar Açık Kapılardır — Güvenliğini Sağlayın

İçerik otomasyon API'sini (n8n iş akışları, özel entegrasyonlar, harici CMS köprüleri) kullanan her JekCMS sitesi bir webhook endpoint'i ortaya çıkarır. Bu endpoint internetten POST istekleri kabul eder, veri yükünü işler ve veritabanınıza veri yazar. İsteğin gerçekten yetkili göndericinizden geldiğini doğrulamazsanız, URL'yi keşfeden herkes sitenize içerik enjekte edebilir.

JekCMS'in buna cevabı tek ama sağlam bir katman: her webhook isteğinde HMAC-SHA256 imza doğrulaması. Bu çok katmanlı bir güvenlik paketi değil — açık deliği kapatan, iyi uygulanmış tek bir kontrol. Bu yazı, bu kontrolün tam olarak ne yaptığını ve kurulumunuz daha fazlasını gerektiriyorsa üzerine kendiniz neler ekleyebileceğinizi anlatıyor.

HMAC-SHA256 İmzalama Nasıl Çalışır

HMAC (Hash-based Message Authentication Code), paylaşılan bir gizli anahtar kullanarak her istek için benzersiz bir imza oluşturur. Gönderici gizli anahtarı kullanarak istek gövdesinin bir hash'ini hesaplar, bunu başlık olarak ekler ve alıcı aynı hash'i yeniden hesaplayarak isteğin değiştirilmediğini ve gizli anahtarı bilen birinden geldiğini doğrular.

Algoritma basit bir dille:

  1. Gönderici veri yükünü JSON'a serileştirir
  2. Gönderici HMAC-SHA256(json_govde, gizli_anahtar) hesaplar
  3. Gönderici isteği başlıkta hash ile gönderir: X-Webhook-Signature: sha256=abc123...
  4. Alıcı ham istek gövdesini okur
  5. Alıcı kendi gizli anahtar kopyasını kullanarak aynı HMAC'i hesaplar
  6. Alıcı iki hash'i karşılaştırır — eşleşirlerse istek gerçektir

Gizli anahtar asla ağ üzerinden seyahat etmez. Birisi isteği yakalasa bile, anahtarı bilmeden geçerli bir imza oluşturamaz.

JekCMS Gelen Webhook'ları Nasıl Doğrular

JekCMS'in webhook endpoint'i, X-Webhook-Signature başlığını, ham istek gövdesinden ve N8N_WEBHOOK_SECRET'ınızdan hesaplanan bir hash'e karşı kontrol eder:

<?php
$rawBody = file_get_contents('php://input');

$signatureHeader = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
if (strpos($signatureHeader, 'sha256=') !== 0) {
    http_response_code(401);
    exit;
}
$receivedSignature = substr($signatureHeader, 7);

$expectedSignature = hash_hmac('sha256', $rawBody, N8N_WEBHOOK_SECRET);

if (!hash_equals($expectedSignature, $receivedSignature)) {
    http_response_code(401);
    exit;
}

// Imza dogrulandi — veri yukunu isle

Kontrolün tamamı bu: bir hash hesaplaması, bir zamanlama güvenli karşılaştırma. Yerleşik bir zaman damgası penceresi, tekrar deposu ya da IP izin listesi yoktur. İmza eşleşmiyorsa, istek iş mantığınıza dokunmadan reddedilir.

hash_equals Neden Önemli

Karşılaştırma === yerine hash_equals() kullanır. Bu bir stil tercihi değil — bir güvenlik gereksinimidir. Standart dize karşılaştırması (===), ilk uyumsuz karakterde erken çıkar; yani daha fazla karakter eşleşen imzaları reddetmek biraz daha uzun sürer. Bir saldırgan bu zamanlama farklarını ölçerek, her seferinde bir karakter olmak üzere geçerli bir imzayı yeniden oluşturabilir — buna zamanlama saldırısı denir. hash_equals() kaç karakter eşleştiğine bakmaksızın her zaman aynı miktarda zaman alır ve bu yan kanalı tamamen ortadan kaldırır.

Bu Katmanın Kapsamadığı Şeyler — Ve Kendiniz Nasıl Eklersiniz

Tek bir imza kontrolü en yaygın saldırıyı durdurur (URL'nizi bulan ama gizli anahtarınızı bilmeyen bir saldırgan). Ancak tek başına, yakalanmış bir isteğin tekrar oynatılmasına karşı koruma sağlamaz ve endpoint'e hangi IP'lerin ulaşabileceğini kısıtlamaz. Kurulumunuz bu ek sertleştirmeyi gerektiriyorsa, hiçbiri hazır gelmez — ama hepsini aynı işleyicide eklemek basittir.

İsteğe Bağlı: Zaman Damgası Tabanlı Tekrar Koruması

İmza geçerli olsa bile eski, yakalanmış istekleri reddetmek isterseniz, göndericinizin imzalanan içeriğe bir zaman damgası eklemesini sağlayın ve gelen istekte yaşını kontrol edin:

// Gonderici: imzalanan iceriğe bir zaman damgasi ekleyin
$timestamp = time();
$signedContent = $timestamp . '.' . $jsonBody;
$signature = hash_hmac('sha256', $signedContent, $secret);
// $timestamp ve $signature'i ayri basliklar olarak gonderin

// Alici: birkac dakikadan eski her seyi reddedin
$age = abs(time() - $timestamp);
if ($age > 300) {
    http_response_code(401);
    exit;
}
$expected = hash_hmac('sha256', $timestamp . '.' . $rawBody, $secret);
if (!hash_equals($expected, $receivedSignature)) {
    http_response_code(401);
    exit;
}

Bu, her iki uçta da koordinasyon gerektirir — göndericiniz (örneğin bir n8n iş akışı) zaman damgasını alıcınızın beklediği şekilde eklemeli ve imzalamalıdır.

İsteğe Bağlı: IP İzin Listesi

Webhook göndericiniz her zaman bilinen, sabit bir IP'den veya aralıktan geliyorsa — kontrolünüzdeki bir n8n örneği gibi — imza kontrolü çalışmadan önce temel bir izin listesi kontrolü ekleyebilirsiniz; böylece beklenmeyen adreslerden gelen istekler hash hesaplamasına hiç CPU harcanmadan reddedilir:

function ip_in_range(string $ip, string $range): bool {
    if (strpos($range, '/') === false) {
        return $ip === $range;
    }
    [$subnet, $bits] = explode('/', $range);
    $ipLong = ip2long($ip);
    $subnetLong = ip2long($subnet);
    $mask = -1 << (32 - (int)$bits);
    return ($ipLong & $mask) === ($subnetLong & $mask);
}

$allowed = ['10.0.0.0/8', '203.0.113.50'];
$clientIp = $_SERVER['REMOTE_ADDR'];
$ok = false;
foreach ($allowed as $range) {
    if (ip_in_range($clientIp, $range)) { $ok = true; break; }
}
if (!$ok) {
    http_response_code(403);
    exit;
}

Bir uyarı: sunucunuz bir ters proxy veya CDN'in arkasındaysa, $_SERVER['REMOTE_ADDR'] orijinal istemcinin değil proxy'nin IP'si olur. Bu durumda X-Forwarded-For veya CF-Connecting-IP başlığına ihtiyacınız vardır — ve bu başlıklara yalnızca tüm trafiğin gerçekten proxy üzerinden geçtiğini doğruladıysanız güvenmelisiniz, aksi halde taklit edilebilirler.

Veri Yükü Doğrulaması Hâlâ Önemli

Doğru imzalanmış bir istek yine de kötü veri içerebilir. Webhook'un ne yapması gerekiyorsa — bir gönderi yayımlamak, medya eklemek, zamanlanmış bir görevi tetiklemek — veri yükünün şeklini ve alan uzunluklarını veritabanınıza dokunmadan önce doğrulayın; tehlikeli alanları filtrelemeye çalışmak yerine beklenmeyen alanları olan her şeyi reddedin. Beklenen anahtarların basit bir izin listesi, her birinde tür ve uzunluk kontrolüyle, fazla kod yazmadan bozuk ya da kötü niyetli veri yüklerinin büyük çoğunluğunu yakalar.

Anahtar Rotasyonu

Webhook gizli anahtarınızı düzenli olarak rotasyona sokun. JekCMS'te yerleşik bir çift-anahtar geçiş dönemi yoktur, bu yüzden rotasyon kısa, koordineli bir pencere anlamına gelir: gizli anahtarı hem gönderici tarafında hem JekCMS'in ortam yapılandırmasında yaklaşık aynı anda güncelleyin ve eski anahtarla gönderilen bir isteğin doğrulamayı geçemeyeceği kısa bir aralığı hesaba katın. Çoğu entegrasyon için bu, birkaç ayda bir kimlik bilgisi rotasyonu yapmanın kabul edilebilir bir bedelidir; kesintisiz bir rotasyon istiyorsanız, yukarıdaki doğrulama kontrolünü geçiş sırasında iki gizli anahtarı kabul edecek şekilde genişletmeniz gerekir.

Gizli Bilgi Sızdırmadan Kayıt Tutma

Bir webhook başarısız olduğunda nedenini bilmeniz gerekir — ama neyi kaydettiğinize dikkat edin. Gizli anahtarı, tam imzayı veya hassas içerik barındırabilecek eksiksiz istek gövdesini asla kaydetmeyin. Zaman damgasını, kaynak IP'yi, kısaltılmış bir user-agent'ı ve red nedenini kaydetmek genellikle sorunu teşhis etmeye yeter: tek bir IP'den gelen imza hataları dalgası neredeyse her zaman açık webhook endpoint'lerini tarayan bir bot demektir, gerçek bir entegrasyon sorunu değil.

Yukarıdaki HMAC kontrolü istek başına ihmal edilebilir bir yük ekler. Sitenize bir API aracılığıyla giren içeriğin gerçekten yetkilendirildiğini bilmek için bu küçük bir bedeldir.

Hemen Sipariş Verin

Tek seferlik ödeme, ömür boyu erişim. Kurulum 30 dakika.

Fiyatlara Bak
  • 30 dakikada kurulum ve yayın
  • 14+ profesyonel tema
  • n8n otomasyon entegrasyonu
  • Otomatik SEO — Sitemap, Schema.org
  • iyzico ödeme entegrasyonu

Yeniliklerden ilk sen haberdar ol

Yeni özellikler, sürüm notları ve CMS rehberleri — ayda birkaç e-posta, spam yok.