Blog
Seguridad

Las capas de seguridad de Simmetric Chat: claves API, webhooks firmados y DLP

Cómo Simmetric Chat autentica cada petición, hashea las claves API con HMAC-SHA256, firma webhooks y Web Push, y redacta datos personales con filtros DLP.

Simmetric Team10 min de lectura08/09/2026

La seguridad es una pila, no un interruptor

Una plataforma de chat que custodia los documentos de tu empresa debe ganarse la confianza por capas: cómo se autentican las peticiones, cómo se emite y conserva el acceso programático, cómo las integraciones en segundo plano prueban su legitimidad y qué ocurre con los contenidos sensibles mientras atraviesan prompts y respuestas. Simmetric Chat aborda cada uno de estos aspectos con un mecanismo nombrado, y v0.22 cerró algunas de las lagunas más sutiles - comparaciones timing-safe de secretos, login resistente a la enumeración y un motor DLP que ahora cubre también los identificadores europeos estructurados. Este artículo recorre la pila de la puerta de entrada hacia dentro.

Tres formas en que las peticiones se autentican

Cada endpoint bajo /api cae en uno de tres regímenes de credenciales:

  • JWT Bearer (primario). Los usuarios humanos se autentican vía el endpoint de login o registro y reciben un JWT firmado. Cada token lleva un claim jti verificado contra una lista de revocación (opcionalmente apoyada en Redis), para que la desconexión o la revocación administrativa surtan efecto de inmediato, no al vencer. Los tokens inválidos o expirados reciben un 401 limpio; el middleware resuelve el usuario junto con roles y permisos en cada petición.
  • Clave API (`X-Api-Key`). El acceso programático - la superficie de cuenta de servicio del widget y las claves creadas por los usuarios vía los endpoints API-key - usa claves prefijadas verificadas contra un digest HMAC, descritas más abajo.
  • Secreto compartido del collector. Las llamadas servicio-a-servicio del collector de ingestión llevan X-Collector-Secret, comparado en tiempo constante con una guarda de longitud. Este era el último lugar donde sobrevivía una comparación en claro de secretos en el servidor, y v0.22 lo cerró: los callbacks de importación de archivos ahora usan la misma disciplina crypto.timingSafeEqual que cualquier otra barrera de secretos.

Sobre la autenticación se colocan las guardas RBAC tratadas en un artículo aparte - controles de permisos, barreras admin y prevención de IDOR en el acceso a workspaces y proyectos. La autenticación responde a «quién eres»; el RBAC responde a «qué puedes tocar».

Claves API: HMAC-SHA256, cifradas en reposo

Una clave API es una credencial portadora, así que la forma en que el servidor la conserva importa tanto como la forma en que la verifica. Simmetric Chat emite claves con un prefijo sk- reconocible - familiar para los ecosistemas de herramientas que la mayoría de los desarrolladores ya usa - y nunca conserva la clave misma. En reposo, cada clave existe solo como digest HMAC-SHA256 calculado bajo un secreto dedicado del lado del servidor, API_KEY_HMAC_SECRET:

text
sk-abc123… (emitida una vez, mostrada una vez al llamante)
 │  HMAC-SHA256(API_KEY_HMAC_SECRET, clave)
 ▼
key_hash conservado en api_keys - la clave misma es irrecuperable

El diseño tiene dos propiedades deliberadas:

  • Rotación desacoplada. API_KEY_HMAC_SECRET es independiente de JWT_SECRET y de ENCRYPTION_KEY. Rotar la clave de firma de las sesiones no invalida las claves API, y rotar la clave de cifrado en reposo no rompe la verificación de claves. Cada secreto tiene una sola tarea.
  • Verificación en tiempo constante. La verificación es una búsqueda del digest HMAC con clave - O(1), sin límites take sobre un escaneo de candidatos. Es lo que hace que la autenticación con clave API sea lo bastante barata para estar en cada petición en un despliegue multi-instancia.

Los usuarios gestionan sus propias claves vía los endpoints API-key: creación a demanda, listado a demanda, revocación a demanda. La revocación elimina la capacidad de reconstruir una credencial válida; el digest ya no coincide con nada.

Webhooks firmados y Web Push

Las integraciones salientes deben ser verificables tanto como las entrantes.

Los webhooks se firman con HMAC-SHA256. El servidor calcula una firma sobre el payload usando el secreto del webhook, y tu servicio receptor recalcula el digest antes de confiar en el cuerpo del evento. Un endpoint receptor nunca debe confiar en un llamante que dice ser Simmetric Chat - puede probarlo, byte a byte, con su propia copia del secreto. Un endpoint de eventos de prueba te permite ejercitar un receptor sin generar actividad real en la plataforma.

El Web Push usa el protocolo VAPID para las notificaciones del navegador. El servidor tiene un par de claves VAPID; la clave pública se expone a los clientes autenticados vía un endpoint de sistema, las suscripciones se gestionan mediante endpoints explícitos subscribe/unsubscribe, y los administradores pueden enviar un push de prueba para verificar la pipeline de punta a punta. Ambos canales están siempre activos en el nivel Community - la firma y el push son comportamiento base de la plataforma, no funcionalidad enterprise.

Rate limiting en la frontera

El rate limiting está estratificado por superficie, con las habituales cabeceras RateLimit-* emitidas en las rutas limitadas:

  • Limiter API global - 200 peticiones por minuto por IP en todas las rutas en producción
  • Limiter de autenticación - 10 peticiones por minuto en los endpoints de escritura de la autenticación, la barrera más estricta porque los endpoints de credenciales son los primeros objetivos de los abusos
  • Limiter de leads del widget - 3 peticiones por hora en la captura de leads, porque un formulario público es donde se concentra el abuso automatizado
  • Limiter de probe - 10 peticiones por minuto en los endpoints de probe de conectividad, para que el test del asistente de configuración no pueda convertirse en arma

Cuando REDIS_URL está configurado, los contadores viven en un store Redis compartido para que los límites signifiquen lo mismo en cada instancia; si no, cada instancia mantiene su propio store. Las peticiones que llevan una cabecera de widget saltan el limiter global - el tráfico de widgets ya viene throttled aguas arriba por el limiter por clave del servicio widget - y no hay un limiter dedicado al chat, porque el agente impone internamente concurrencia por usuario, presupuestos de tokens y timeouts de reloj.

DLP: redacción antes de la exfiltración

La prevención de pérdida de datos en Simmetric Chat es un plugin de filtro que escanea tanto el prompt entrante como la respuesta saliente - incluidos los flushes progresivos token a token del streaming - y redacta las coincidencias antes de que el contenido salga de tu red. El escáner reconoce 10 clases de patterns PII integrados:

  • Direcciones de correo
  • Números de tarjeta de crédito
  • Claves API y claves privadas
  • Más los identificadores europeos estructurados: Partita IVA italiana, codice fiscale e IBAN, añadidos en v0.22 y sembrados de forma idempotente

La configuración de patterns está respaldada por base de datos y gestionada por admins: activar o desactivar cualquier pattern por fila, añadir hasta 50 patterns personalizados con validación en vivo de la compilación y vista previa de prueba, e inspeccionar un panel de historial de coincidencias DLP filtrable por origen (chat o widget). Las expresiones regulares integradas están congeladas - puedes desactivar un pattern integrado pero no reescribirlo - mientras que los patterns personalizados llevan tus definiciones. Los escaneos que pueden leer los patterns configurados los usan a través de una caché de TTL corto y recaen en el conjunto integrado si la base de datos es inalcanzable, para que una interrupción de la base nunca desactive la redacción.

Dos detalles de gobernanza completan el cuadro. Un ajuste DLP_BYPASS_ROLES permite a los admins eximir roles específicos del escaneo, y cada bypass genera un evento de auditoría que registra quién bypassó y en qué superficie - nunca el contenido escaneado. Los administradores también pueden revelar o volver a ocultar los textos coincidentes a través de una conversación con un único interruptor, con visibilidad limitada a la sesión y oculta por defecto, para que la redacción siga siendo reversible para una revisión autorizada pero no en silencio.

El endurecimiento más sutil de v0.22

Los pequeños cambios importan porque cierran los canales que los atacantes realmente sondean:

  • Comparaciones timing-safe en todas partes. Cada comparación en claro de secretos que quedaba - las barreras del secreto del collector, el callback de importación de archivos, el control de clave cache-bust del widget - usa ahora crypto.timingSafeEqual con una guarda de longitud y falla en modo cerrado cuando el secreto esperado no está definido.
  • Login resistente a la enumeración. Cuando un nombre de usuario no existe, el login ejecuta de todos modos una comparación ficticia de hash antes de responder, para que el tiempo de respuesta no distinga ya a los usuarios existentes de los inexistentes. Los cuerpos inválidos devuelven un 400 estructurado en lugar de un 401 que dejaría filtrar los internos de Zod.
  • Configuraciones erróneas que fallan en voz alta. Una mala configuración HMAC del lado del servidor en la verificación de claves API devuelve 500, por elección - un secreto mal configurado nunca debe disfrazarse de fallo de autenticación.
  • Validación estructurada. Los cuerpos de las peticiones se validan con esquemas Zod compartidos vía safeParse; cada error es un sobre uniforme con detalles por campo, para que los clientes fallen de forma predecible.

Toda la superficie API - tablas de endpoints, encuadre de eventos SSE y requisitos de autenticación por ruta - está documentada en la referencia API, y una interfaz Swagger en vivo está incluida en el servidor.

Lee la guía completa en la documentación →

Artículos relacionados