Verificación y Seguridad
Verifica las firmas de webhooks de Whatalo usando HMAC-SHA256 para prevenir solicitudes forjadas y ataques de replay.
Cada solicitud de webhook de Whatalo incluye una firma HMAC-SHA256. Siempre verifica esta firma antes de procesar cualquier payload de evento — garantiza que la solicitud se originó en Whatalo y no ha sido manipulada.
Verificación con el SDK (Simple)
Para la mayoría de los plugins, el helper del SDK es el camino más rápido:
import { verifyWebhook } from "@whatalo/plugin-sdk/webhooks";
// rawBody must be the raw, unparsed request body string
const isValid = verifyWebhook({
payload: rawBody,
signature: req.headers["x-webhook-signature"] as string,
timestamp: req.headers["x-webhook-timestamp"] as string,
secret: process.env.WHATALO_CLIENT_SECRET!,
});
if (!isValid) {
return res.status(401).json({ error: "Invalid signature" });
}Esto realiza la verificación HMAC-SHA256 usando tu secreto de cliente como clave y aplica la ventana predeterminada de protección contra replay de 300 segundos.
Verificación Manual
Usa el helper del SDK cuando sea posible. Si necesitas un verificador personalizado, conserva las mismas validaciones:
import crypto from "node:crypto";
function verifyWhataloWebhook(
headers: Record<string, string | string[] | undefined>,
rawBody: string,
secret: string
): boolean {
const timestamp = getHeader(headers, "x-webhook-timestamp");
const signature = getHeader(headers, "x-webhook-signature");
if (!timestamp || !signature || !/^[a-f0-9]{64}$/i.test(signature)) return false;
const timestampValue = Number(timestamp);
if (!Number.isInteger(timestampValue)) return false;
const ageSeconds = Math.abs(Math.floor(Date.now() / 1000) - timestampValue);
if (ageSeconds > 300) return false;
const expected = crypto
.createHmac("sha256", secret)
.update(`${timestamp}.${rawBody}`, "utf8")
.digest("hex");
try {
return crypto.timingSafeEqual(
Buffer.from(signature, "hex"),
Buffer.from(expected, "hex")
);
} catch {
return false;
}
}
function getHeader(
headers: Record<string, string | string[] | undefined>,
name: string
): string {
const value = headers[name];
return Array.isArray(value) ? value[0] ?? "" : value ?? "";
}Encabezados Enviados con Cada Webhook
| Encabezado | Descripción |
|---|---|
X-Webhook-Id | Identificador único de entrega — úsalo para verificaciones de idempotencia |
X-Webhook-Event | Tipo de evento (e.g., order.created) |
X-Webhook-Signature | Firma HMAC-SHA256 |
X-Webhook-Timestamp | Marca de tiempo Unix de cuándo se generó la firma |
Algoritmo de Firma
Whatalo genera la firma de la siguiente manera:
- Concatenar:
${timestamp}.${rawBody} - Calcular HMAC-SHA256 usando tu secreto de cliente como clave
- Codificar el resultado en hexadecimal
- Enviar como
X-Webhook-Signature
Puedes replicar esto en cualquier lenguaje:
import crypto from "node:crypto";
function computeSignature(rawBody: string, timestamp: string, secret: string): string {
const signedContent = `${timestamp}.${rawBody}`;
return crypto
.createHmac("sha256", secret)
.update(signedContent)
.digest("hex");
}Lista de Verificación de Seguridad
Omitir cualquiera de estas verificaciones expone tu plugin a solicitudes forjadas o reproducidas.
- Usa el body sin procesar — Parsea el JSON solo después de la verificación. Cualquier modificación al body antes de calcular el HMAC causará que la verificación falle.
- Compara firmas en tiempo constante — Usa
crypto.timingSafeEqualo el helper del SDK. La igualdad de cadenas (===) es vulnerable a ataques de timing. - Aplica la ventana de replay — Rechaza solicitudes con un
X-Webhook-Timestampde más de 5 minutos. - Valida
X-Webhook-Event— Solo procesa tipos de eventos que tu plugin declaró en el manifiesto. - Guarda
X-Webhook-Idpara idempotencia — Las entregas de webhooks pueden reintentarse. Procesa cada ID de entrega solo una vez.
Prueba de Webhooks Localmente
Usa el CLI para disparar eventos de prueba contra tu servidor de desarrollo local:
# Trigger an order.created event against your dev store
whatalo webhook trigger ORDER_CREATED --store mi-tienda-devEl CLI firma la solicitud con tu secreto de cliente de desarrollo, por lo que tu lógica de verificación funciona exactamente igual que en producción. Solo funciona con tiendas de desarrollo.
Consulta la Referencia CLI — webhook para la lista completa de eventos de prueba soportados.