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 platformundan 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 <code className="bg-secondary px-2 py-1 rounded">X-Wespoke-Signature</code> 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 <strong>Ayarlar → Webhooks</strong> bölümünden alabilirsiniz.
const crypto = require('crypto');
const express = require('express');
const app = express();
// To get the raw body
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;
}
// Timestamp check (reject requests older than 5 minutes)
const currentTime = Date.now();
if (Math.abs(currentTime - parseInt(timestamp)) > 5 * 60 * 1000) {
return false;
}
// Signature calculation
const payload = `${timestamp}.${req.rawBody}`;
const expectedSignature = 'sha256=' +
crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
// Secure comparison against timing attacks
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' });
}
// Signature verified, process webhook
const { event, data } = req.body;
// Process the event...
console.log(`Webhook received: ${event}`);
res.status(200).json({ received: true });
});
app.listen(3000);import hmac
import hashlib
import time
import os
import { getTranslations } from 'next-intl/server';
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
# Timestamp check (reject requests older than 5 minutes)
current_time = int(time.time() * 1000)
if abs(current_time - int(timestamp)) > 5 * 60 * 1000:
return False
# Signature calculation
payload = f"{timestamp}.{request.get_data(as_text=True)}"
expected_signature = 'sha256=' + hmac.new(
secret.encode(),
payload.encode(),
hashlib.sha256
).hexdigest()
# Secure comparison against timing attacks
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
# Signature verified, process webhook
data = request.json
event = data.get('event')
# Process the event...
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;
}
// Timestamp check (reject requests older than 5 minutes)
$currentTime = round(microtime(true) * 1000);
if (abs($currentTime - intval($timestamp)) > 5 * 60 * 1000) {
return false;
}
// Signature calculation
$rawBody = file_get_contents('php://input');
$payload = $timestamp . '.' . $rawBody;
$expectedSignature = 'sha256=' . hash_hmac('sha256', $payload, $secret);
// Secure comparison against timing attacks
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;
}
// Signature verified, process webhook
$data = json_decode(file_get_contents('php://input'), true);
$event = $data['event'] ?? '';
// Process the event...
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