Praxsuite

Seguridad de Endpoints

Vincent Depassier · 30 de agosto de 2026

Un endpoint es una URL pública sin API key adelante. Cualquiera que averigüe la dirección puede hacerle POST. Esta página es sobre asegurarte de que solo quien vos quisiste pueda hacer que algo pase.


Por dónde pasa un request

En orden, y cada paso lo puede detener:

  Llega el POST
     │
     ├─ ¿el endpoint existe y está Activo?     no → 404
     ├─ ¿origen permitido, si hay reglas?      no → 403
     ├─ ¿cuerpo dentro del límite del plan?    no → 413
     ├─ ¿firma válida, si está configurada?    no → 401
     │
     ▼
  se guarda el evento, después corre la automatización

Dos cosas del orden. La verificación de origen ocurre antes de leer el cuerpo, así que un origen rechazado no cuesta nada. Y el evento se guarda después de validar, así que tu historial de eventos es una lista de requests legítimos — una avalancha de llamadas falsificadas no lo llena.


Verificación de firma

La autenticación real. Quien manda calcula un HMAC del cuerpo con un secreto que ambos tienen, lo pone en un header, y el gateway lo recalcula y compara.

Configurás tres cosas:

Ajuste

Ejemplo

Nombre del header

Stripe-Signature, X-Hub-Signature-256

Algoritmo

HmacSha256 o HmacSha512

Secreto

El secreto compartido, guardado cifrado

El secreto no se vuelve a mostrar después de definirlo, y se puede regenerar desde el menú del endpoint — que es además cómo se rota.

Dos formatos, porque la industria tiene dos

Default — firma el cuerpo crudo. El header lleva el digest en hex, opcionalmente con prefijo sha256= o sha512=. Es lo que hacen GitHub y la mayoría de los webhooks genéricos.

X-Hub-Signature-256: sha256=7d38cdd689735b008b3c702edd92eea23791c5f6

Timestamp-punto-payload — firma "{timestamp}.{cuerpo}", y el header lleva ambos:

Stripe-Signature: t=1614556823,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd

Es la forma de Stripe y Slack. Elegí la que documente quien te manda; equivocarse produce un desajuste de firma que se ve exactamente igual que un secreto equivocado.

La comparación es de tiempo constante, así que una firma incorrecta no revela cuán incorrecta era.

`None` significa que cualquiera lo puede llamar. Un endpoint sin firma configurada acepta cualquier POST de cualquiera que sepa la URL. A veces es justo lo que querés — un formulario de contacto público cuya automatización solo inserta una fila — pero debería ser una decisión, no un descuido. Si la automatización escribe algo que importa, o cuesta plata correrla, configurá una firma.


El handshake de challenge

Algunos servicios verifican que la URL es tuya antes de mandarte nada. Las plataformas de Meta hacen esto: te hacen GET con hub.mode, hub.verify_token y hub.challenge, y esperan que devuelvas el challenge como texto plano.

Definí un verify token en el endpoint y el gateway responde ese handshake por vos:

GET /{workspaceId}/endpoint/{endpointId}?hub.mode=subscribe
                                        &hub.verify_token=tu-token
                                        &hub.challenge=1158201444
→ 200  1158201444

Un token que no coincide responde 403, y también lo hace un GET a un endpoint sin verify token configurado — el handshake está apagado salvo que lo enciendas.


Reglas de origen

Una regla de origen restringe desde qué sitios web puede llamarse un endpoint. Importa para una forma puntual: un endpoint Sync llamado por JavaScript de tu propio sitio.

Patrón

Coincide con

https://app.example.com

exactamente ese origen

*.example.com

cualquier subdominio de example.com

http://localhost:3000

desarrollo local

Un endpoint sin reglas de origen acepta todos los orígenes. Es el único lugar del gateway que falla abierto en vez de cerrado, y la razón es que la mayoría de los endpoints los llaman servidores, que no mandan header Origin — negar por defecto habría roto todos los webhooks el día que existió la funcionalidad.

De ahí la limitación que conviene decir sin vueltas: las reglas de origen son un control de navegador, no una frontera de seguridad. El header Origin lo pone el navegador y cualquier cosa que no sea un navegador puede omitirlo o falsificarlo. Evitan que tu endpoint sea llamado desde la página web de otro; no evitan que lo llame un curl. Para eso está la firma.

Los orígenes se validan al guardarlos, tienen un tope de cantidad según tu plan, y se de-duplican.

La otra lista de orígenes

Las credenciales tienen su propia lista, separada:

Lista

Restringe

Orígenes del endpoint

qué sitios pueden hacerle POST a ese endpoint

Orígenes de la credencial

qué sitios pueden usar esa API key

Se configuran en lugares distintos y ninguna implica la otra. La de credencial es la que usás para atar una key pk_live_ a tu propio dominio, para que una copia sacada de tu bundle no funcione desde la página de otro. Aplica la misma advertencia: restringe navegadores, no servidores.


Recomendaciones prácticas

  • Configurá siempre una firma en un endpoint cuya automatización escriba. La URL va a terminar en un log, un archivo de configuración o un ticket de soporte tarde o temprano.

  • Rotá regenerando el secreto y después actualizá a quien manda. Hay una ventana entre ambos pasos donde las llamadas fallan — hacelo cuando unos minutos de reintentos sean aceptables, que para la mayoría de los emisores lo son.

  • Usá reglas de origen en endpoints Sync que llame tu sitio, y no dependas de ellas para nada más.

  • Desactivá en vez de eliminar un endpoint que retirás, así sobrevive el historial de eventos.

  • Mirá la lista de eventos primero cuando algo se rompe. Distingue "nunca llegó" de "llegó y falló", y esas dos cosas tienen causas completamente distintas.


Siguiente