un

guest
1 / ?
back to lessons

Encabezados como Bolsas

Los marcos de registro HTTP tratan los encabezados de solicitud como una bolsa de pares clave-valor. La API de registro expone la bolsa completa. Los operadores habilitan el registro de encabezados para depuración: cuando una solicitud falla, los encabezados cuentan la historia. Sin lista de denegación incorporada. Sin filtrado de credenciales en la documentación. Encabezados completos a disco.

Los encabezados de credenciales en una solicitud típica:

- Authorization: Bearer eyJhbGciOiJIUzI1NiJ9... (token JWT o OAuth)

- Cookie: session=abc123; auth=xyz789

- X-API-Key: sk-live-abc123...

- X-Auth-Token: ghp_abc123... (patrón de token de acceso personal de GitHub)

Estos valores autentican la solicitud. Escritos en un archivo de registro, autentican cualquier solicitud.

La Línea de Credenciales

Una credencial escrita en un archivo de registro no se queda en un lugar. Viaja:

1. Servidor web escribe a /var/log/nginx/access.log

2. Agente de rotación de registros (logrotate) copia a /var/log/nginx/access.log.1

3. Envío de registros (Fluentd, Filebeat, Logstash) lee y envía a agregador

4. Agregador de registros (Elasticsearch, Splunk, Datadog) indexa y almacena

5. Retenido durante 30-90 días bajo la política predeterminada

La credencial existe en todos los cinco lugares simultáneamente. Revocar el token de sesión no elimina la credencial del agregador de registros. Permanece searchable, exportable y accesible para cualquiera con acceso a los registros durante todo el plazo de retención.

La Ventana de Exposición

Ventana de exposición para una credencial en memoria: max(duración de la sesión, vida útil del proceso). Sesión: horas a días. Proceso: horas a semanas.

Ventana de exposición para una credencial en un registro: max(duración de la sesión, retención del registro). Sesión: horas a días. Retención: 30-90 días.

Una credencial robada de la memoria requería que el atacante estuviera presente durante la ventana de sesión. Una credencial robada de un registro requiere solo acceso al agregador de registros, disponible de manera retrospectiva, durante todo el período de retención.

MOAD-0003 vs MOAD-0004

MOAD-0003 (Contexto Revelado): una credencial en memoria se filtra al manejador de solicitud equivocado. Accesible solo durante la ventana del proceso, a través de la piscina de hilos. Ephemeral.

MOAD-0004 (Logged Secret): una credencial en el disco persiste a través de la rotación de registros, el envío de registros y la agregación de registros. Accesible de manera retroactiva, para cualquier persona con acceso a los registros, durante 30-90 días. Persistente.

La diferencia estructural: temporal vs persistente. La solución opera en un nivel diferente.

Temporal vs Persistente

La distinción entre temporal y persistente determina la superficie de riesgo, el nivel de la solución y los requisitos de respuesta a incidentes.

Por qué el MOAD-0004 presenta un mayor riesgo que el MOAD-0003? Compara en qué lugar vive cada credencial y durante cuánto tiempo.

Lista de denegación de credenciales en el nivel de serialización

La solución: una lista de denegación de credenciales en el nivel de serialización. Antes de que cualquier valor de encabezado llegue a la salida de registro, comprueba el nombre del encabezado contra una lista de denegación. Reemplaza el valor con [REDACTED].

CREDENTIAL_HEADERS = {
    'authorization',
    'cookie',
    'x-api-key',
    'x-auth-token',
    'x-csrf-token',
    'proxy-authorization',
}

def sanitize_headers(headers: dict) -> dict:
    return {
        k: '[REDACTED]' if k.lower() in CREDENTIAL_HEADERS else v
        for k, v in headers.items()
    }

La lista de denegación pertenece al nivel de serialización, no al nivel de consulta de registros. Ocultación de consultas de registros: se aplica después de que el crédito llega al disco; el valor bruto sigue existiendo, solo ocultado para la visualización. Ocultación en el nivel de serialización: el crédito nunca llega al disco. El valor bruto nunca entra en el archivo de registro, en el envíador de registros o en el acumulador de registros.

Prueba de la lista de denegación

Tres patrones de prueba:

- Positivo: una solicitud con Authorization: Bearer token123 produce una entrada de registro con Authorization: [REDACTED]

- Negativo: una solicitud con Content-Type: application/json produce una entrada de registro con el valor intacto

- Case-insensitive: AUTHORIZATION: Bearer token123 también produce [REDACTED] (nombres de encabezados HTTP case-insensitive)

La lista de denegación requiere mantenimiento: nuevos patrones de encabezados de credenciales (por ejemplo, encabezados personalizados X-Service-Auth) necesitan agregarlos de manera explícita. La solución es estructural pero no se mantiene automáticamente.

Aplicar la lista de denegación

Un equipo configura el formato de registro de acceso de su Nginx para incluir todos los encabezados de solicitud para depurar un incidente de producción. La configuración:

log_format debug_format '$remote_addr - $request - $http_authorization - $http_cookie';
access_log /var/log/nginx/debug.log debug_format;

Resuelven el incidente e intentan eliminar la configuración de depuración, pero el cambio no llega a producción antes del siguiente ciclo de despliegue (7 días más tarde).

Identifica el defecto. ¿Qué encabezados de credenciales podrían estar expuestos? Describe el enfoque de la lista de denegación: dónde se aplica, qué verifica y qué produce?