Un punto de acceso de estado que es general en público y detallado en privado
Una página de estado pública es útil, y también un regalo para los atacantes: el estado activo/caído por servicio, la latencia, los nombres de host internos y las IP son un mapa en vivo de su infraestructura. Queríamos la señal de salud sin el reconocimiento. Este es el patrón.
El problema
Nuestro front end desacoplado muestra una pequeña franja de estado. Consultaba un punto de acceso /api/system-status de Drupal que devolvía detalle por servicio a todo el mundo: Postgres, Redis, Solr, la malla, la monitorización, el almacenamiento, hasta una IP interna de la LAN. Un llamador anónimo obtenía un inventario completo de servicios y un mapa de interrupciones.
La forma
Dos audiencias, un punto de acceso:
- Anónimo recibe un resumen general:
{ status: "ok" | "degraded", time }. Suficiente para mostrar un punto verde o rojo. Sin nombres de servicio, sin latencia, sin direcciones. - Un llamador autorizado recibe el desglose completo por servicio.
La cuestión es cómo demuestra el front end que está autorizado sin enviar una credencial al navegador.
De servidor a servidor, no de navegador a servidor
El navegador nunca ve el secreto. El propio servidor del front end renderiza la franja: consulta Drupal desde el servidor, adjunta un secreto compartido en una cabecera y pasa al cliente solo el resultado general. El secreto vive en el entorno del servidor, nunca en un paquete de código.
// front-end server -> Drupal (secret stays server-side)
fetch(statusUrl, { headers: { "x-status-secret": process.env.STATUS_SECRET } })Drupal desbloquea la respuesta detallada cuando la cabecera coincide —comparada en tiempo constante— o cuando el llamador tiene el permiso de administrador. Todos los demás reciben el resumen.
$detailed = $user->hasPermission('administer site configuration')
|| hash_equals($configured, $provided);Detalles que importan
- Comparación en tiempo constante. Use
hash_equals()(ocrypto.timingSafeEqual), nunca==, para que el secreto no pueda recuperarse midiendo tiempos. - Mantenga privada la respuesta detallada. Márquela como no-store y varíe según la cabecera del secreto, para que una caché compartida nunca sirva el detalle a una solicitud anónima.
- Seguro ante el orden de despliegue. Hasta que el secreto esté presente en ambos lados, el punto de acceso devuelve el resumen general. Una cabecera que Drupal aún no acepta, o un secreto que el front end aún no envía, se degradan ambos a un resultado seguro para el público, de modo que los cambios de back end, front end e infraestructura pueden lanzarse en cualquier orden.
- Falla en modo cerrado. Sin secreto configurado, el detalle está desactivado para todos, no activado.
El resultado
La Internet pública ve un solo bit honesto: activo o degradado. Los operadores y el servidor del front end lo ven todo. El mapa de infraestructura nunca sale del límite de confianza, y la señal de salud sigue funcionando.