# İmza Doğrulama (https://yapl.app/tr/docs/user-guides/webhooks/verifying-signatures)

# Webhook İmzalarını Doğrulama

YAPL'dan gelen her webhook teslimatı, alıcı servisinizin isteğin gerçek olduğunu ve değiştirilmediğini doğrulayabilmesi için bir kriptografik imza içerir. Bu, saldırganların uç noktanıza sahte webhook yükleri göndermesini önler.

## Nasıl Çalışır

1. Bir webhook oluşturduğunuzda YAPL benzersiz bir **imzalama sırrı** üretir
2. Her teslimat için YAPL, sırrınızı ve yükü kullanarak bir HMAC-SHA256 imzası hesaplar
3. İmza, `X-YAPL-Signature-256` istek başlığına eklenir
4. Servisiniz aynı sırrı kullanarak imzayı yeniden hesaplar ve karşılaştırır

İmzalar eşleşirse teslimat gerçektir.

## Teslimat Başlıkları

Her webhook teslimatı şu başlıkları içerir:

| Başlık | Açıklama | Örnek |
|--------|----------|-------|
| `X-YAPL-Signature-256` | HMAC-SHA256 imzası | `sha256=a1b2c3d4...` |
| `X-YAPL-Event` | Olay türü | `project.created.v1` |
| `X-YAPL-Delivery-ID` | Benzersiz teslimat tanımlayıcısı | `del_abc123` |
| `X-YAPL-Timestamp` | İmzanın oluşturulduğu zaman (ISO 8601) | `2026-03-25T10:30:00.000Z` |

## İmza Hesaplama

İmza, zaman damgası ile ham JSON gövdesinin birleşmesi üzerinden hesaplanır:

```
imzalanabilir_yük = zaman_damgası + "." + ham_json_gövde
imza = "sha256=" + HMAC-SHA256(sır, imzalanabilir_yük)
```

Zaman damgası, tekrar saldırılarını önlemek için dahil edilmiştir — bir saldırgan geçerli bir teslimatı yakalasa bile, zaman damgası farklı olacağı için yeniden kullanamaz.

## Doğrulama Örnekleri

### Node.js

```javascript
const crypto = require('crypto');

function verifyWebhook(secret, signature, timestamp, body) {
  const signablePayload = `${timestamp}.${body}`;
  const hmac = crypto.createHmac('sha256', secret);
  hmac.update(signablePayload, 'utf8');
  const expected = `sha256=${hmac.digest('hex')}`;

  // Zamanlama saldırılarını önlemek için sabit zamanlı karşılaştırma kullanın
  if (signature.length !== expected.length) return false;
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// Uç nokta işleyicinizde:
app.post('/webhook', (req, res) => {
  const signature = req.headers['x-yapl-signature-256'];
  const timestamp = req.headers['x-yapl-timestamp'];
  const body = req.rawBody; // Ham istek gövdesi (string olarak)

  if (!verifyWebhook(SIZIN_SIRRINIZ, signature, timestamp, body)) {
    return res.status(401).send('Geçersiz imza');
  }

  // Webhook'u işleyin
  const event = JSON.parse(body);
  console.log(`${event.type} alındı:`, event.data);
  res.status(200).send('OK');
});
```

### Python

```python
import hmac
import hashlib

def verify_webhook(secret, signature, timestamp, body):
    signable_payload = f"{timestamp}.{body}"
    expected = "sha256=" + hmac.new(
        secret.encode('utf-8'),
        signable_payload.encode('utf-8'),
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(signature, expected)

# Uç nokta işleyicinizde (Flask örneği):
@app.route('/webhook', methods=['POST'])
def handle_webhook():
    signature = request.headers.get('X-YAPL-Signature-256')
    timestamp = request.headers.get('X-YAPL-Timestamp')
    body = request.get_data(as_text=True)

    if not verify_webhook(SIZIN_SIRRINIZ, signature, timestamp, body):
        return 'Geçersiz imza', 401

    event = request.get_json()
    print(f"{event['type']} alındı: {event['data']}")
    return 'OK', 200
```

### Go

```go
package main

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "fmt"
    "io"
    "net/http"
)

func verifyWebhook(secret, signature, timestamp, body string) bool {
    signablePayload := fmt.Sprintf("%s.%s", timestamp, body)
    mac := hmac.New(sha256.New, []byte(secret))
    mac.Write([]byte(signablePayload))
    expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))

    return hmac.Equal([]byte(signature), []byte(expected))
}

func webhookHandler(w http.ResponseWriter, r *http.Request) {
    signature := r.Header.Get("X-YAPL-Signature-256")
    timestamp := r.Header.Get("X-YAPL-Timestamp")
    body, _ := io.ReadAll(r.Body)

    if !verifyWebhook(sizinSirriniz, signature, timestamp, string(body)) {
        http.Error(w, "Geçersiz imza", http.StatusUnauthorized)
        return
    }

    // Webhook'u işleyin
    w.WriteHeader(http.StatusOK)
    w.Write([]byte("OK"))
}
```

## Güvenlik Önerileri

### Her zaman imzaları doğrulayın

Test için bile imza doğrulamasını atlamayın. Doğrulanmamış uç noktalar sahte isteklere karşı savunmasızdır.

### Sabit zamanlı karşılaştırma kullanın

Zamanlama saldırılarını önlemek için her zaman sabit zamanlı karşılaştırma fonksiyonları kullanın (Node.js'de `crypto.timingSafeEqual` veya Python'da `hmac.compare_digest` gibi).

### Zaman damgasını kontrol edin

Tekrar saldırılarını önlemek için `X-YAPL-Timestamp` başlığının güncel olduğunu doğrulayın (örn. son 5 dakika içinde):

```javascript
const deliveryTime = new Date(timestamp).getTime();
const now = Date.now();
const fiveMinutes = 5 * 60 * 1000;

if (Math.abs(now - deliveryTime) > fiveMinutes) {
  return res.status(401).send('Teslimat çok eski');
}
```

### Sırları güvenli şekilde saklayın

- Sırları asla kaynak koduna yazmayın
- Ortam değişkenleri veya sır yöneticisi kullanın
- İhlal şüpheniz varsa yeni bir webhook oluşturarak sırrı yenileyin

### HTTPS kullanın

Alıcı uç noktanız, webhook yükünü aktarım sırasında korumak için her zaman HTTPS kullanmalıdır. YAPL, üretim webhook URL'leri için HTTPS gerektirir.

## İlgili Konular

- [Webhook Oluşturma](/docs/user-guides/webhooks/creating-webhooks) — Uç noktaları oluşturun ve imzalama sırrınızı alın
- [Olay Türleri](/docs/user-guides/webhooks/event-types) — Teslimatları tetikleyen olaylar
- [Teslimat Kayıtları](/docs/user-guides/webhooks/delivery-logs) — Teslimat durumunu izleyin