Skip to main content

Criptografía y Seguridad en Webhooks (X-SaaSCol-Signature)

Cómo es hoy: HMAC implementado en el Event Bus Go. El envelope incluye tenant_id y product.
Parcial: cola de reintentos con backoff productivo.

Cuando ocurren eventos críticos en el ecosistema (catálogo canónico v1: cms.content.published, bot.interaction.lead_captured, crm.opportunity.converted, etc.), el bus SaaSCol Core (Redis) despacha notificaciones HTTP POST a URLs configuradas por tenant o integradores (Make, n8n, Zapier).

Para evitar falsificaciones y garantizar que los paquetes no hayan sido adulterados en tránsito, todo webhook entrante o saliente va autenticado de forma obligatoria mediante la cabecera criptográfica:

X-SaaSCol-Signature: <hmac_sha256_hex_digest>


1. Algorithmic Foundation (HMAC SHA-256)

El sello criptográfico se genera aplicando una función hash HMAC SHA-256 sobre el cuerpo crudo de la petición JSON (raw body string), utilizando como llave de cifrado el secreto único asignado a tu sucursal (tenant_webhook_secret).

Signature = HMAC-SHA256(Key_tenant, Payload_raw)


2. Implementaciones Oficiales de Verificación en 3 Lenguajes

A continuación presentamos las implementaciones certificadas para validar webhooks en tu infraestructura receptora antes de procesar transacciones bancarias o datos contables:

⚡ Node.js / TypeScript

import crypto from 'crypto';

export function verifySaaSColSignature(rawBody: string, receivedHeader: string, tenantSecret: string): boolean {
if (!receivedHeader || !tenantSecret) return false;

const expectedSignature = crypto
.createHmac('sha256', tenantSecret)
.update(rawBody, 'utf8')
.digest('hex');

// Comparación criptográfica segura en tiempo constante (evita Timing Attacks)
try {
return crypto.timingSafeEqual(
Buffer.from(expectedSignature, 'utf8'),
Buffer.from(receivedHeader, 'utf8')
);
} catch {
return false;
}
}

🐹 Go (Golang)

package webhooks

import (
"crypto/hmac"
"crypto/sha256"
"crypto/subtle"
"encoding/hex"
)

func VerifySaaSColSignature(rawBody []byte, receivedHeader string, tenantSecret string) bool {
if receivedHeader == "" || tenantSecret == "" {
return false
}

mac := hmac.New(sha256.New, []byte(tenantSecret))
mac.Write(rawBody)
expectedSignature := hex.EncodeToString(mac.Sum(nil))

// Comparación en tiempo constante para mitigar ataques de temporización
return subtle.ConstantTimeCompare([]byte(expectedSignature), []byte(receivedHeader)) == 1
}

🐍 Python (FastAPI / Django)

import hmac
import hashlib

def verify_saascol_signature(raw_body: bytes, received_header: str, tenant_secret: str) -> bool:
if not received_header or not tenant_secret:
return False

expected_signature = hmac.new(
tenant_secret.encode('utf-8'),
msg=raw_body,
digestmod=hashlib.sha256
).hexdigest()

# Comparación segura en tiempo constante
return hmac.compare_digest(expected_signature, received_header)

3. Política de Reintentos (Backoff Exponencial)

Si el endpoint externo responde con códigos de error HTTP 5xx o experimenta una caída temporal de red (ECONNREFUSED), el despachador central reintentará el envío en intervalos de backoff exponencial (1m, 5m, 15m, 1h, 6h) antes de registrar el evento como fallido en los registros de auditoría (audit_logs).