Webhook isteklerinin güvenliğini sağlamak için imza doğrulama nasıl yapılır
Wespoke, gönderdiği tüm webhook isteklerini bir HMAC-SHA256 imzası ile imzalar. Bu imzayı doğrulayarak webhook'un gerçekten Wespoke'tan geldiğinden emin olabilirsiniz.
Önemli: Webhook imza doğrulamasını uygulamanız şiddetle önerilir. Bu, kötü niyetli kullanıcıların sahte webhook istekleri göndermesini engeller.
Her webhook isteği X-Wespoke-Signature header'ı içerir. Bu header, isteğin gövdesinin HMAC-SHA256 hash'ini içerir.
POST /webhook HTTP/1.1
Host: your-server.com
Content-Type: application/json
X-Wespoke-Signature: sha256=1234567890abcdef...
X-Wespoke-Timestamp: 1696774496789
{
"event": "call.started",
"data": {...}
}İmza, webhook secret'ınız kullanılarak şu şekilde hesaplanır:
HMAC-SHA256(secret, timestamp + "." + request_body)Webhook secret'ınızı kontrol panelinde Ayarlar → Webhooks bölümünden alabilirsiniz.
const crypto = require('crypto');
const express = require('express');
const app = express();
// Raw body'yi almak için
app.use(express.json({
verify: (req, res, buf) => {
req.rawBody = buf.toString();
}
}));
function verifyWebhookSignature(req, secret) {
const signature = req.headers['x-wespoke-signature'];
const timestamp = req.headers['x-wespoke-timestamp'];
if (!signature || !timestamp) {
return false;
}
// Zaman damgası kontrolü (5 dakikadan eski istekleri reddet)
const currentTime = Date.now();
if (Math.abs(currentTime - parseInt(timestamp)) > 5 * 60 * 1000) {
return false;
}
// İmza hesaplama
const payload = `${timestamp}.${req.rawBody}`;
const expectedSignature = 'sha256=' +
crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
// Timing attack'lara karşı güvenli karşılaştırma
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
app.post('/webhook', (req, res) => {
const webhookSecret = process.env.WESPOKE_WEBHOOK_SECRET;
if (!verifyWebhookSignature(req, webhookSecret)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// İmza doğrulandı, webhook işle
const { event, data } = req.body;
// Olayı işle...
console.log(`Webhook received: ${event}`);
res.status(200).json({ received: true });
});
app.listen(3000);import hmac
import hashlib
import time
from flask import Flask, request, jsonify
app = Flask(__name__)
def verify_webhook_signature(request, secret):
signature = request.headers.get('X-Wespoke-Signature')
timestamp = request.headers.get('X-Wespoke-Timestamp')
if not signature or not timestamp:
return False
# Zaman damgası kontrolü (5 dakikadan eski istekleri reddet)
current_time = int(time.time() * 1000)
if abs(current_time - int(timestamp)) > 5 * 60 * 1000:
return False
# İmza hesaplama
payload = f"{timestamp}.{request.get_data(as_text=True)}"
expected_signature = 'sha256=' + hmac.new(
secret.encode(),
payload.encode(),
hashlib.sha256
).hexdigest()
# Timing attack'lara karşı güvenli karşılaştırma
return hmac.compare_digest(signature, expected_signature)
@app.route('/webhook', methods=['POST'])
def webhook():
webhook_secret = os.environ.get('WESPOKE_WEBHOOK_SECRET')
if not verify_webhook_signature(request, webhook_secret):
return jsonify({'error': 'Invalid signature'}), 401
# İmza doğrulandı, webhook işle
data = request.json
event = data.get('event')
# Olayı işle...
print(f"Webhook received: {event}")
return jsonify({'received': True}), 200
if __name__ == '__main__':
app.run(port=3000)<?php
function verifyWebhookSignature($secret) {
$signature = $_SERVER['HTTP_X_WESPOKE_SIGNATURE'] ?? '';
$timestamp = $_SERVER['HTTP_X_WESPOKE_TIMESTAMP'] ?? '';
if (empty($signature) || empty($timestamp)) {
return false;
}
// Zaman damgası kontrolü (5 dakikadan eski istekleri reddet)
$currentTime = round(microtime(true) * 1000);
if (abs($currentTime - intval($timestamp)) > 5 * 60 * 1000) {
return false;
}
// İmza hesaplama
$rawBody = file_get_contents('php://input');
$payload = $timestamp . '.' . $rawBody;
$expectedSignature = 'sha256=' . hash_hmac('sha256', $payload, $secret);
// Timing attack'lara karşı güvenli karşılaştırma
return hash_equals($signature, $expectedSignature);
}
// Webhook endpoint
$webhookSecret = getenv('WESPOKE_WEBHOOK_SECRET');
if (!verifyWebhookSignature($webhookSecret)) {
http_response_code(401);
echo json_encode(['error' => 'Invalid signature']);
exit;
}
// İmza doğrulandı, webhook işle
$data = json_decode(file_get_contents('php://input'), true);
$event = $data['event'] ?? '';
// Olayı işle...
error_log("Webhook received: " . $event);
http_response_code(200);
echo json_encode(['received' => true]);Webhook imza doğrulamanızı test etmek için kontrol panelinde bulunan webhook test aracını kullanabilirsiniz. Bu araç, gerçek bir webhook isteği simüle eder ve imza doğrulamanızın doğru çalışıp çalışmadığını kontrol etmenizi sağlar.
Webhook Test Aracına Git