Tema 17

17. Manejo de errores, mensajes seguros y prevención de fuga de información

Cuando una API falla, no solo importa que responda algo útil; también importa cuánto revela sobre su estructura interna, sus datos y sus reglas. Los errores son una superficie de observación privilegiada para atacantes: muestran diferencias de comportamiento, validaciones, estados de negocio, existencia de recursos y detalles técnicos que pueden convertirse en un mapa del sistema.

Objetivo Responder fallos de forma útil sin exponer información sensible
Enfoque Errores consistentes, observabilidad interna y exposición mínima
Resultado Reducir enumeración, profiling y filtraciones por mensajes de error

17.1 Introducción

Los errores son inevitables en cualquier API. Habrá validaciones fallidas, recursos inexistentes, tokens vencidos, conflictos de negocio, timeouts, dependencias caídas y excepciones inesperadas. El desafío no está en evitar que algo falle, sino en fallar de forma controlada.

Una API insegura suele responder errores demasiado expresivos: revela stack traces, nombres internos, diferencias sutiles entre estados, o devuelve mensajes que permiten inferir usuarios válidos, existencia de objetos o lógica operativa. En cambio, una API madura distingue entre lo que necesita saber el cliente legítimo y lo que solo debe quedar registrado internamente.

Este tema estudia cómo diseñar respuestas de error útiles, consistentes y seguras.

17.2 Qué puede filtrarse a través de un error

Los errores pueden revelar mucho más de lo que parece. No solo exponen texto; también exponen estructura, timing, diferencias entre caminos de ejecución y detalles del entorno.

Ejemplos de información filtrable:

  • Existencia o no de usuarios y recursos.
  • Estados internos del negocio.
  • Nombres de tablas, columnas, servicios o rutas internas.
  • Stack traces, librerías y versiones.
  • Payloads sensibles o valores inválidos completos.
  • Diferencias de privilegio y autorización.
Para un atacante, un error bien observado es una respuesta estructurada sobre cómo piensa el sistema.

17.3 Objetivos de un buen manejo de errores

Una respuesta de error segura debería cumplir varios objetivos al mismo tiempo:

  • Ser comprensible para el cliente legítimo.
  • No exponer más información de la necesaria.
  • Ser consistente entre endpoints y situaciones similares.
  • Permitir trazabilidad interna para soporte e investigación.
  • Diferenciar adecuadamente entre errores del cliente, del negocio y fallos del servidor.

17.4 Consistencia como control de seguridad

La consistencia no es solo una cuestión estética o de DX. También es una defensa. Cuando una API responde de forma muy distinta ante casos equivalentes, ofrece señales útiles para enumeración y profiling.

Por ejemplo:

  • Un login que responde distinto para usuario inexistente y contraseña errónea.
  • Un endpoint que devuelve `403` si el recurso existe y `404` si no existe.
  • Mensajes diferentes según el rol necesario para acceder.

Estas diferencias pueden facilitar reconocimiento del sistema incluso sin acceso válido.

17.5 Errores del cliente versus errores del servidor

Una API debería distinguir claramente entre problemas causados por la solicitud y fallos internos del sistema. Esta separación ayuda al cliente y evita mezclar errores de uso con problemas operativos.

Tipo de error Ejemplo Qué conviene mostrar
Entrada inválida Formato incorrecto, campo faltante Qué parte del contrato falló
Autenticación/autorización Token inválido, acceso denegado Mensaje controlado sin exceso de detalle
Conflicto de negocio Estado incompatible, operación no permitida Regla funcional relevante, no internals
Fallo interno Excepción, dependencia caída Mensaje genérico y trazabilidad interna

17.6 Validación fallida: cuánto detalle conviene dar

Los errores de validación suelen requerir más detalle porque el cliente necesita corregir la solicitud. Sin embargo, ese detalle debe limitarse al contrato de entrada, no a la lógica interna del backend.

Es razonable indicar:

  • Qué campo es inválido.
  • Qué formato o restricción se esperaba.
  • Qué campos obligatorios faltan.

No es razonable devolver:

  • Excepciones internas del framework.
  • Modelos internos completos.
  • Payloads sensibles completos en eco.
  • Reglas privadas o heurísticas antiabuso.

17.7 Autenticación y enumeración

Los flujos de autenticación son especialmente sensibles a errores informativos. Diferenciar demasiado entre “usuario inexistente”, “contraseña incorrecta”, “cuenta bloqueada” o “MFA pendiente” puede facilitar enumeración y profiling de cuentas.

Esto no significa responder siempre igual en todo sentido, pero sí evitar mensajes que confirmen información innecesaria a actores no confiables. Muchas veces conviene devolver respuestas más uniformes externamente y guardar el detalle real en logs internos.

17.8 Autorización y diferencia entre 403 y 404

En algunos casos, responder `403 Forbidden` confirma implícitamente que el recurso existe, pero que el actor no puede acceder. En otros contextos puede ser preferible usar `404 Not Found` para no confirmar existencia de recursos sensibles.

No hay una única respuesta correcta para todas las APIs. Lo importante es que la política sea consciente, consistente y alineada con el modelo de amenaza. La inconsistencia es lo que más ayuda al atacante.

17.9 Excepciones no controladas

Las excepciones no controladas son una fuente clásica de fuga de información. Cuando la API deja que una excepción suba hasta el borde sin manejo central, puede terminar devolviendo stack traces, nombres de clases, consultas, rutas de archivo o detalles de infraestructura.

Esto suele ocurrir por:

  • Modo debug habilitado.
  • Middlewares de error mal configurados.
  • Dependencias que formatean errores automáticamente.
  • Falta de capa unificada de manejo de excepciones.

17.10 Manejadores centralizados de error

Una práctica recomendable es centralizar la traducción de errores internos a respuestas HTTP. Esto permite:

  • Uniformar estructura y códigos.
  • Redactar mensajes seguros.
  • Asociar identificadores de correlación.
  • Registrar detalle técnico solo donde corresponde.
  • Evitar diferencias accidentales entre endpoints.

La centralización reduce exposición y mejora la mantenibilidad del comportamiento de error.

17.11 Correlation IDs y trazabilidad interna

Un cliente legítimo o un operador puede necesitar reportar un fallo sin que la respuesta incluya información técnica sensible. Para eso son útiles los identificadores de correlación: valores que permiten encontrar el evento exacto en logs internos sin exponer internals al exterior.

Esto permite mantener el mensaje externo simple, mientras el equipo de soporte conserva suficiente trazabilidad para investigar.

17.12 Timeouts, dependencias y respuestas degradadas

Cuando fallan servicios externos o dependencias internas, la API debe decidir cómo comunicarlo. Un error demasiado verboso puede exponer arquitectura; uno demasiado ambiguo puede dificultar la operación del cliente.

En estos casos conviene:

  • Evitar nombrar directamente sistemas internos si no es necesario.
  • Indicar que la operación no pudo completarse en ese momento.
  • Registrar internamente el componente exacto y el contexto técnico.
  • Considerar respuestas degradadas cuando el negocio lo permita.

17.13 Errores y datos sensibles

Los errores no deberían incluir secretos, tokens, payloads completos, documentos ni datos personales salvo que exista una razón muy fuerte y controlada. Esto vale también para sistemas de tracing, debugging y pantallas de soporte.

Una práctica peligrosa es “ecoar” el request fallido entero en la respuesta o en herramientas de soporte. Eso puede convertir un error común en una fuga directa de información sensible.

17.14 Timing y comportamiento observable

No toda fuga viene del texto. También puede surgir del tiempo de respuesta o del patrón observable. Si una API tarda claramente distinto cuando un usuario existe o cuando un recurso pertenece a otro tenant, el atacante puede usar esas señales para inferir información.

Por eso la seguridad de errores también incluye prestar atención a:

  • Diferencias temporales significativas.
  • Secuencias de validación que filtran estados.
  • Pasos condicionales visibles desde afuera.

17.15 Formato estándar de errores

Usar un formato uniforme para errores ayuda tanto al cliente como a la seguridad. Una estructura consistente puede incluir:

  • Un código de error estable.
  • Un mensaje entendible y acotado.
  • Campos opcionales de validación si aplica.
  • Un identificador de correlación.

Lo importante es que el formato no obligue a volcar detalle técnico excesivo para ser útil.

17.16 Ambientes de desarrollo versus producción

En desarrollo suele ser útil ver más detalle. El problema aparece cuando esa misma verbosidad se arrastra a staging público o producción. La configuración de errores debe diferenciar claramente ambientes y minimizar exposición en cualquier entorno accesible fuera del equipo controlado.

También conviene evitar que capturas, trazas o payloads reales de producción terminen en documentación o canales informales por costumbre de debugging.

17.17 Errores frecuentes

  • Devolver stack traces o nombres internos en respuestas.
  • Diferenciar demasiado entre usuario inexistente y credencial incorrecta.
  • Exponer payloads completos o secretos en errores de validación.
  • No centralizar el manejo de excepciones.
  • Usar códigos y mensajes inconsistentes según el endpoint.
  • Confiar en debug o logs accesibles como si fueran privados por definición.
  • Olvidar que el tiempo de respuesta también puede filtrar información.

17.18 Qué debes recordar de este tema

  • Los errores son una superficie de fuga de información y profiling del sistema.
  • Una respuesta de error segura debe ser útil, consistente y limitada en detalle.
  • La validación y el negocio pueden requerir mensajes específicos, pero sin exponer internals.
  • Las excepciones no controladas son una fuente clásica de filtración.
  • Correlation IDs, logging interno y manejo centralizado permiten soporte sin sobreexposición.

17.19 Conclusión

Manejar errores de forma segura es una parte esencial de la seguridad de APIs REST porque el sistema revela mucho sobre sí mismo precisamente cuando algo sale mal. Diseñar respuestas consistentes, útiles y cuidadosamente limitadas evita que un mecanismo orientado a soporte se convierta en una herramienta de reconocimiento para atacantes. La clave está en separar claramente lo que necesita el cliente de lo que solo debe saber el sistema.

En el próximo tema estudiaremos seguridad en diseño: versionado, idempotencia y minimización de exposición, para ver cómo decisiones arquitectónicas tempranas condicionan la superficie de ataque de la API.