8 min de lectura

Precedencia de cabeceras HTTP: detén los conflictos de identidad de la API

La precedencia de cabeceras HTTP puede dividir la identidad de una API entre clientes y proxies. Aprende a rechazar de forma segura cabeceras Authorization y personalizadas duplicadas.

Precedencia de cabeceras HTTP: detén los conflictos de identidad de la API

Una solicitud con dos credenciales no es una solicitud con autenticación de respaldo. Es una instrucción ambigua que se entrega a una cadena de programas que puede interpretarla de forma distinta en cada salto. He visto equipos pasar horas culpando a una API después de que un proxy seleccionara silenciosamente un valor de Authorization y la aplicación seleccionara otro. El síntoma parece aleatorio hasta que alguien imprime las cabeceras sin procesar en cada límite.

La precedencia de las cabeceras HTTP necesita una regla que puedas expresar en una sola frase, probar directamente en la red y aplicar antes de autenticar: una solicitud que proporcione más de un valor para un mismo campo de credenciales sensible para la seguridad debe fallar. No elijas el primero. No elijas el último. No unas los valores con una coma. Esas decisiones convierten un comportamiento accidental de la implementación en tu política de autenticación.

Esto importa más allá de Authorization. Muchas API aceptan X-API-Key, una cabecera personalizada de tenant, una marca de tiempo para solicitudes firmadas o un campo de identidad reenviado. Cuando las credenciales atraviesan clientes, balanceadores, traductores de protocolos y middleware de aplicaciones, el tratamiento de duplicados pasa a formar parte del límite de seguridad.

HTTP no establece un ganador general

HTTP define la sintaxis de los campos y proporciona reglas especiales de combinación para algunos campos repetidos, pero no dice que el primer campo Authorization gane en todas partes ni que el último gane en todas partes. El receptor debe interpretar la sección de campos recibida según la semántica del campo y su propia implementación.

RFC 9110 indica que un receptor puede combinar varias líneas de campo con el mismo nombre en un único valor separado por comas cuando la definición del campo permite una lista separada por comas. También indica que no debe combinar las líneas cuando la definición del campo no lo permite. Esta distinción se difumina con frecuencia. «Las cabeceras se pueden combinar» no es una regla para todas las cabeceras. Es una regla para los campos diseñados como listas.

Accept ofrece un contraste útil. Un cliente puede enviar varias líneas Accept, y un receptor normalmente puede tratar sus valores como una única lista de tipos de contenido aceptables. Authorization transporta credenciales para una solicitud. No es una lista genérica de credenciales intercambiables. Una coma también puede tener significado dentro de la sintaxis de un esquema de autenticación. Unir dos valores puede crear una cadena que ninguno de los clientes pretendía y que distintos analizadores interpretan de maneras diferentes.

Los nombres de los campos de cabecera no distinguen entre mayúsculas y minúsculas. Estos son duplicados:

Authorization: Bearer token-a
authorization: Bearer token-b

Un detector que compare la escritura original no detectará este caso. Normaliza el nombre antes de contar los valores.

No confundas las líneas de campo duplicadas con varios desafíos de autenticación en WWW-Authenticate. Un servidor puede anunciar varios esquemas aceptables en una respuesta. Es el servidor ofreciendo opciones. Una solicitud con dos valores Authorization es el cliente presentando credenciales que compiten entre sí. Son problemas distintos y necesitan tratamientos diferentes.

La misma advertencia se aplica cuando una API admite un campo de credenciales estándar y otro personalizado. Una API podría aceptar deliberadamente Authorization: Bearer ... o X-API-Key: .... Si la documentación de la API no define cómo resolver ambos juntos, enviar los dos produce un conflicto de identidad. Recházalo. Un mecanismo alternativo que solo existe en el middleware de alguien no es un contrato.

Los clientes facilitan los duplicados más de lo que parece

Que un cliente pueda emitir cabeceras repetidas depende del modelo de solicitudes de la biblioteca. Las bibliotecas que exponen las cabeceras como un mapa suelen sobrescribir un valor cuando el código asigna dos veces el mismo nombre. Las que exponen un array o una colección multivalor pueden enviar ambos. Ninguno de estos comportamientos demuestra qué recibirá el siguiente salto.

Con curl, repite -H para solicitar dos campos:

curl --http1.1 -v https://api.example.test/orders \
  -H 'Authorization: Bearer first' \
  -H 'Authorization: Bearer second'

El registro detallado debería mostrar dos líneas de salida parecidas a estas:

> Authorization: Bearer first
> Authorization: Bearer second

Eso solo demuestra la solicitud HTTP/1.1 de salida de curl en esa conexión. No demuestra que el perímetro, el balanceador o la aplicación hayan recibido ambos valores. Prueba un endpoint controlado que administres antes de usar este patrón contra una API de producción. Los tokens de los ejemplos deben ser desechables, y los tokens Bearer reales nunca deben aparecer en una grabación del terminal ni en un ticket de soporte.

En JavaScript, el objeto Headers habitual tiene una semántica que sorprende a muchas personas. set() reemplaza el valor actual. append() añade conceptualmente otro valor, pero la serialización y la semántica de la cabecera siguen siendo importantes. Un desarrollador puede creer que envió dos cabeceras cuando la biblioteca construyó en realidad un valor unido por comas. Precisamente por eso las pruebas de autenticación deben inspeccionar la entrada sin procesar, no solo un objeto en memoria.

El código de servidor de Node.js tiene su propia trampa. req.headers suele exponer nombres normalizados y puede mostrar una vista agrupada. req.rawHeaders conserva una lista alterna de nombres y valores recibidos en solicitudes HTTP/1.1. Un diagnóstico seguro debe contar los nombres normalizados a partir de la representación sin procesar y evitar imprimir valores secretos:

function duplicateNames(rawHeaders) {
  const counts = new Map();
  for (let i = 0; i < rawHeaders.length; i += 2) {
    const name = rawHeaders[i].toLowerCase();
    counts.set(name, (counts.get(name) || 0) + 1);
  }
  return [...counts.entries()].filter(([, count]) => count > 1);
}

console.log(duplicateNames(req.rawHeaders));
// Example output: [ [ 'authorization', 2 ] ]

Úsalo como ayuda de diagnóstico, no como permiso para analizar manualmente todas las cabeceras de una aplicación. El framework o la pasarela deben realizar el rechazo efectivo en el primer punto de confianza. El objetivo es mostrar lo que ocultaba el objeto de cabeceras simplificado.

Las cabeceras personalizadas merecen la misma desconfianza. Un cliente puede añadir accidentalmente X-API-Key dos veces mediante una capa de cabeceras predeterminadas y otra específica de la solicitud. También puede enviar un valor Authorization heredado de un wrapper corporativo del cliente mientras el código añade explícitamente una clave API. La API podría parecer funcionar durante las pruebas locales porque la ruta local no tiene ese wrapper. Luego producción recibe ambas credenciales y se comporta de otra manera.

Los proxies pueden cambiar la solicitud y las pruebas disponibles

Un proxy inverso es un receptor HTTP y un nuevo emisor HTTP. No se limita a transportar bytes del cliente a la aplicación. Analiza la solicitud entrante, aplica la configuración, puede traducir protocolos y escribe una solicitud nueva hacia el servidor ascendente. Eso le da muchas oportunidades para conservar duplicados, descartarlos, combinarlos o crear una nueva cabecera de credenciales.

El caso peligroso es la interpretación dividida. Imagina que un cliente envía:

Authorization: Bearer attacker-token
Authorization: Bearer service-token

Un componente perimetral conserva el primer valor para comprobar el acceso. La biblioteca del servidor ascendente presenta el último valor a la aplicación. El perímetro autoriza una identidad y la aplicación realiza el trabajo como otra. Aunque ninguno de los componentes tenga un error de análisis, la cadena no asigna un significado único a la solicitud.

Un fallo más corriente es menos espectacular y más frecuente. La configuración de un proxy añade un campo Authorization ascendente para una credencial de servicio, pero olvida eliminar el que llega del cliente. El servicio de destino elige uno según un comportamiento que nadie documentó. Una actualización posterior del proxy, una migración de ruta o un cambio de HTTP/1.1 a HTTP/2 modifica qué valor sobrevive. El equipo lo llama una interrupción intermitente de autenticación porque nunca registró el duplicado.

Los campos de reenvío crean un problema de identidad relacionado. X-Forwarded-User, X-Forwarded-Client-Cert y las cabeceras de identidad personalizadas suelen viajar desde un perímetro de confianza hasta una aplicación. El perímetro expuesto públicamente debe eliminar las copias proporcionadas por el cliente antes de añadir las suyas. Si reenvía copias no confiables, una aplicación que confíe en la posición equivocada de la lista puede aceptar una identidad falsificada.

La regla cambia ligeramente según el límite de confianza:

  • En la entrada pública, rechaza los campos de autenticación duplicados y elimina las cabeceras de identidad internas proporcionadas por el cliente.
  • En una pasarela de confianza, inyecta la única credencial o cabecera de identidad necesaria para el servidor ascendente después de eliminar las entradas protegidas del cliente.
  • En la aplicación, vuelve a rechazar los duplicados. La protección en la entrada es necesaria, pero los cambios de ruta pueden acabar saltándose las suposiciones iniciales.
  • En los registros, anota el nombre de la cabecera, el número de apariciones, la ruta y el identificador de la solicitud. Registra el esquema de credenciales solo si es seguro hacerlo.

No dependas del comportamiento predeterminado de un proxy sin probarlo. Los valores predeterminados cambian según el producto, el módulo, el protocolo y la configuración. Un ajuste que trata las cabeceras de respuesta duplicadas no te dice nada sobre las credenciales de solicitud duplicadas. Lee la documentación de la directiva o el middleware exactos y envía después una solicitud duplicada real por la ruta desplegada.

HTTP/2 y HTTP/3 eliminan la sintaxis antigua, no la ambigüedad

HTTP/2 y HTTP/3 no envían líneas de cabecera textuales por la red, pero siguen transportando una secuencia de campos de cabecera. Las reglas del protocolo prohíben los campos pseudo-cabecera duplicados, como :method, y exigen que aparezcan antes que los campos normales. Estas reglas ayudan a mantener la corrección del protocolo. No proporcionan una regla universal de precedencia para Authorization.

Un endpoint HTTP/2 puede recibir varios campos de cabecera normales. Una biblioteca puede exponerlos como valores separados, como un valor combinado o como un error, según el campo y su API. HTTP/3 plantea la misma preocupación práctica en el nivel de la aplicación. Debes probar las versiones del protocolo que acepta tu perímetro.

La traducción entre protocolos es donde se deterioran las suposiciones. Un cliente se comunica por HTTP/2 con una CDN o un balanceador. La CDN se comunica por HTTP/1.1 con una pasarela. La pasarela se comunica por HTTP/2 con un servicio. Cada salto debe traducir una representación de cabeceras. Si el primer salto agrupa un campo y el segundo lo conserva, la aplicación final no puede reconstruir la solicitud original. Es otra razón para que el primer receptor de confianza rechace la ambigüedad en lugar de intentar recuperarla de forma ingeniosa más adelante.

HTTP/2 también trata de forma distinta las cabeceras específicas de la conexión. Campos como Connection están prohibidos porque describen el comportamiento de conexión de HTTP/1.1. Eso no afecta a la precedencia de credenciales. No copies una regla de cabecera específica de un protocolo y supongas que protege una cabecera de autenticación personalizada.

Algunos equipos intentan resolver esto usando coincidencias en minúsculas porque HTTP/2 exige nombres de campo en minúsculas en la red. Eso solo corrige un detalle trivial. Los nombres de HTTP/1.1 tampoco distinguen entre mayúsculas y minúsculas, y una pasarela puede recibir HTTP/1.1 antes de recibir HTTP/2. Normaliza los nombres en todas partes.

Construye la matriz de pruebas alrededor de las rutas, no solo de los protocolos. Prueba una solicitud directa a la aplicación en un entorno de prueba, la ruta pública y cualquier ruta interna usada por trabajadores o herramientas de despliegue. En cada ruta, envía Authorization duplicada, cabeceras de credenciales personalizadas duplicadas y dos canales de credenciales en conflicto. El resultado esperado debe ser el mismo error explícito del cliente en todos los casos.

Tanto elegir el primero como elegir el último crea una superficie de ataque

Protege las acciones con el almacén seguro
Cuando el almacén está bloqueado, Sallyport rechaza todas las acciones hasta que lo desbloquees mediante su puerta de acceso.

«Usa la primera cabecera» parece prudente porque recuerda a un analizador que lee de izquierda a derecha. «Usa la última cabecera» parece práctico porque la configuración posterior debería sobrescribir los valores predeterminados anteriores. Ambas reglas fallan porque el emisor y cada intermediario pueden influir en el orden de manera diferente.

Elegir el primero es vulnerable cuando un atacante puede anteponer una credencial antes de que un componente de confianza añada la suya. Elegir el último es vulnerable cuando un atacante puede añadir una credencial después de que un componente de confianza haya comprobado la primera. El exploit exacto depende del enrutamiento y de la confianza, pero el error de diseño es estable: un componente selecciona una credencial mientras otro ve una solicitud diferente.

Unir con comas es peor que cualquiera de las dos opciones cuando produce una cadena con apariencia válida. Considera una cabecera personalizada de clave API en la que la aplicación separa por comas pero la pasarela compara la cadena completa. O un analizador Bearer que acepta el texto después del primer espacio y no rechaza las comas. Ahora tienes dos lenguajes de análisis para un campo que contiene secretos.

La recomendación popular de «dejar que la API decida» es incorrecta cuando una pasarela realiza cualquier autenticación, limitación de velocidad, enrutamiento por tenant o etiquetado de auditoría antes de que la solicitud llegue a la API. La pasarela ya tomó una decisión de seguridad. Debe usar la misma identidad inequívoca que el servicio o detener la solicitud.

Un contrato predecible tiene este aspecto:

  1. Normaliza todos los nombres de cabecera entrantes.
  2. Cuenta todas las apariciones de los campos protegidos antes de seleccionar las credenciales.
  3. Rechaza los duplicados de cada campo protegido con un error genérico del cliente.
  4. Rechaza los canales de credenciales incompatibles cuando la ruta solo acepta una fuente de identidad.
  5. Elimina los campos protegidos entrantes antes de que un componente de confianza inyecte sus propias credenciales hacia el servidor ascendente.

Hazlo antes de analizar el token. Si el análisis del token se ejecuta primero, un analizador puede consumir un valor que el componente siguiente habría rechazado. Mantén la respuesta de error sencilla. Indica al cliente que la solicitud contiene cabeceras de autenticación en conflicto, pero no repitas sus valores.

Existen API poco frecuentes que definen deliberadamente varios valores para un campo. Si eres responsable de una API de este tipo, documenta la gramática, el orden, el comportamiento ante duplicados y los requisitos del proxy como parte del contrato de autenticación. «El framework se encarga» no es documentación. Si no eres responsable de la API, no inventes un esquema de precedencia para ella.

Las cabeceras personalizadas necesitan un contrato de credenciales, no solo un nombre

Los equipos suelen tratar Authorization como algo sensible y las cabeceras personalizadas como simples elementos de infraestructura. Es al revés. Una cabecera personalizada que selecciona una clave API o un tenant forma parte del material de autenticación, empiece su nombre por X- o no.

Especifica qué canales de credenciales acepta cada ruta. Una ruta puede aceptar un token Bearer en Authorization. Otra puede aceptar una firma de webhook en una cabecera específica junto con una marca de tiempo. Una ruta interna puede recibir una cabecera de identidad únicamente desde una pasarela. Son contratos separados. Evita un middleware general que acepte la primera credencial que encuentre.

Un contrato de credenciales debe responder estas preguntas:

  • ¿Puede aparecer este campo más de una vez?
  • ¿Puede aparecer junto con otro campo de credenciales?
  • ¿Qué componente de confianza puede añadirlo?
  • ¿Lo elimina un proxy antes de reenviarlo?
  • ¿Qué error devuelve la API cuando detecta un conflicto?

Para las claves API, usa uno de dos modelos claros. El primero acepta exactamente un esquema Authorization. El segundo acepta exactamente una cabecera de clave API con nombre propio. No admitas ambos en la misma ruta salvo que exista una necesidad de migración y una regla documentada para los conflictos. Durante una migración, rechaza las solicitudes que contengan ambos y ofrece a los clientes un mensaje de migración que identifique el reemplazo aceptado, sin incluir una fecha que pueda quedar obsoleta. Mantener un mecanismo alternativo silencioso para siempre crea un problema de diagnóstico permanente.

Los webhooks firmados requieren un cuidado adicional. Las cabeceras de firma pueden contener legítimamente parámetros estructurados y una marca de tiempo puede acompañar a la firma. Eso no significa que los campos de firma duplicados sean seguros. Consulta la documentación de verificación del proveedor y conserva el tratamiento esperado del cuerpo sin procesar. Si no define firmas repetidas, recházalas antes de verificar. Nunca las concatènes esperando que la biblioteca de verificación elija la opción prevista.

Las cabeceras de identidad internas son las más fáciles de configurar mal porque resultan prácticas. Si una aplicación acepta X-User-Id desde la red pública y supone que lo insertó un proxy, un cliente puede reclamar cualquier identidad. Vincula las cabeceras internas a una ruta de red privada o a una conexión autenticada con el proxy, elimínalas en cada perímetro público y valida que solo tu proxy de confianza pueda llegar al puerto de la aplicación. La precedencia de cabeceras no puede reparar un límite de confianza de red defectuoso.

Prueba toda la ruta con conflictos intencionados

Mantén el almacén en una sola aplicación
Usa la aplicación firmada para la barra de menús de Mac como límite de credenciales, sin un proceso de almacén independiente.

Las pruebas unitarias de un analizador de tokens no prueban la precedencia de cabeceras. Necesitas una prueba de integración que atraviese los mismos componentes que atraviesa producción. El resultado que buscas es sencillo y estable: toda solicitud ambigua debe rechazarse antes de que se ejecute una acción ascendente.

Empieza con un endpoint inofensivo bajo tu control. Dale un identificador de solicitud y haz que devuelva solo observaciones seguras: nombres de cabecera normalizados, cantidades, versión del protocolo y componente que recibió la solicitud. No devuelvas valores de cabecera. Después colócalo detrás del mismo perímetro, pasarela y enrutamiento de servicio que usa la API objetivo.

Ejecuta un conjunto pequeño de conflictos:

Authorization dos veces, con el mismo valor
Authorization dos veces, con valores diferentes
Authorization junto con X-API-Key
X-API-Key dos veces, con el mismo valor
Una cabecera de identidad interna proporcionada por el cliente junto con la identidad de la pasarela

El caso con el mismo valor importa. Algunos desarrolladores solo rechazan valores diferentes porque consideran inofensivos los valores iguales. Eso crea una distinción de análisis que un atacante puede explorar y deja invisible un error accidental de duplicación. Rechaza cualquier campo protegido duplicado. Un cliente que reintenta con un solo campo todavía puede autenticarse.

Comprueba dos resultados en cada caso. Primero, el cliente recibe una respuesta 4xx explícita del límite que aplica la regla. Segundo, el sistema ascendente no registra ninguna acción bajo ninguna de las dos identidades. Un 401 o un 403 por sí solo no demuestra que la ruta sea segura; un sistema ascendente podría haber procesado parte de la solicitud antes de rechazarla.

Después repite la prueba con cada protocolo y ruta que admitas. Incluye las bibliotecas de cliente usadas por la automatización, no solo curl. Un cliente de línea de comandos, un wrapper de fetch del navegador, una biblioteca HTTP de CI y el runtime de un agente pueden construir las colecciones de cabeceras de forma distinta. Conserva la prueba en tu conjunto de pruebas de despliegue para que una actualización del proxy o del framework no sustituya silenciosamente el rechazo por una regla de selección.

Cuando ocurra un incidente, captura pruebas seguras en orden. Registra cómo se construyó la solicitud del cliente, la decisión de acceso del perímetro, las cabeceras de salida de la pasarela con nombres y cantidades, y la observación de entrada de la aplicación. Correlaciónalas con un único identificador de solicitud. No resuelvas un incidente de cabeceras duplicadas activando el registro completo de cabeceras en producción. Así es como un error de autenticación se convierte en una exposición de credenciales.

Las pasarelas deben controlar la inyección de credenciales de salida

Consulta cada llamada HTTP del agente
El diario de actividad registra cada llamada HTTP del agente sin exponerle la credencial subyacente.

Una pasarela de acciones debe mantener al agente alejado de las credenciales sin procesar y hacer que un único componente sea responsable de la solicitud de salida final. Entregar un token Bearer al agente y pedirle que construya las cabeceras le da autoridad y demasiadas formas de crear una solicitud defectuosa. También dificulta la interpretación de los registros de auditoría cuando las cabeceras predeterminadas y personalizadas entran en conflicto.

Sallyport ejecuta llamadas HTTP con credenciales inyectadas desde su almacén cifrado, en lugar de exponer el secreto al agente. Este límite solo resulta útil si el constructor de solicitudes de salida trata las cabeceras de credenciales como campos protegidos, no como sugerencias que las cabeceras proporcionadas por el agente puedan sobrescribir.

Para una cabecera de salida protegida, la pasarela debe seleccionar la configuración de credenciales guardada, eliminar cualquier instancia proporcionada por el cliente de ese campo sin distinguir entre mayúsculas y minúsculas, y añadir exactamente un valor final. Debe aplicar la misma regla a las cabeceras de credenciales personalizadas. Si la solicitud de destino necesita una cabecera controlada por el agente con el mismo nombre, la configuración es incorrecta o la API de destino necesita otra ruta. No crees una excepción por solicitud que cambie la identidad silenciosamente.

Aquí hay una distinción importante. Eliminar la cabecera Authorization proporcionada por el agente antes de añadir la configurada es apropiado en el límite de salida de confianza. Aceptar dos cabeceras y esperar que el destino las ordene no lo es. La primera acción establece una única fuente de credenciales. La segunda exporta la ambigüedad.

Una pasarela también debe protegerse frente a canales que compiten entre sí. Supón que una conexión guardada inyecta Authorization: Bearer ... mientras la solicitud del agente incluye X-API-Key. El destino podría aceptar cualquiera de las dos. La opción predeterminada más segura es rechazar la solicitud por credenciales en conflicto, salvo que la definición de la conexión permita explícitamente esa combinación y documente el motivo. Una lista de cabeceras permitidas no puede responder a esto porque el significado depende de la API de destino.

Los registros de auditoría deben indicar al operador que la pasarela usó una conexión o etiqueta de credencial concreta, qué host recibió la solicitud, el método, la ruta y si hubo aprobación humana. No deben almacenar el valor de Authorization ni la cabecera personalizada secreta. El diario de actividad de Sallyport está diseñado para registrar llamadas individuales, pero un diario no arregla una solicitud ambigua después de los hechos. El constructor de solicitudes debe eliminar la ambigüedad antes de que salga del equipo.

Los registros revelan fallos de precedencia sin filtrar tokens

Los errores de cabeceras duplicadas sobreviven porque los equipos registran demasiado poco para ver el cambio de ruta o demasiado y provocan un segundo incidente. Puedes registrar lo suficiente para diagnosticar el problema sin conservar credenciales.

Para cada conflicto rechazado, registra una lista normalizada de los nombres de cabecera protegidos y sus cantidades. Añade el nombre de la ruta, el protocolo, el componente receptor, el identificador de la solicitud y un código de motivo como duplicate_authorization o conflicting_credential_channels. Si tu proceso operativo lo permite, registra un identificador de configuración de credenciales que no pueda usarse para recuperar el secreto.

Nunca registres tokens Bearer sin procesar, claves API, valores de autenticación básica, cuerpos de webhooks firmados, cookies ni líneas completas de Authorization. La redacción posterior al formateo de cadenas no es fiable. Una biblioteca puede lanzar una excepción que incluya la solicitud original, o un logger de depuración puede ejecutarse antes que tu redactor. Construye los registros a partir de campos seguros en lugar de volcar la solicitud y tratar de limpiarla después.

Aplicar un hash a un token no es automáticamente seguro. Un hash estable puede permitir que cualquiera con acceso a los registros correlacione el uso de la misma credencial y puede ser vulnerable a intentos de adivinación cuando el secreto tiene poca entropía. Si necesitas correlación, usa un identificador de credencial que no sea secreto y que provenga de tu almacén o configuración. Si no tienes uno, registra que había un canal de credenciales sin nombre y corrige el modelo de configuración.

Trata la falta de evidencias como un fallo de despliegue. Si un perímetro rechaza un duplicado pero el rastro de auditoría no puede mostrar qué perímetro tomó esa decisión, los responsables de responder al incidente perderán tiempo comparando registros de la aplicación que nunca vio la solicitud. Por el contrario, si la aplicación lo rechaza pero el perímetro lo dejó pasar, has encontrado un punto en el que reforzar la aplicación de la regla.

La primera corrección práctica es pequeña: enumera las cabeceras que contienen credenciales en una ruta pública, rechaza las repeticiones y los conflictos en la entrada, y demuestra con una prueba de integración que no se realiza ninguna llamada ascendente. Después aplica el mismo contrato a todas las rutas de proxy y clientes de salida. El orden de las cabeceras nunca debe decidir quién cree una API que está haciendo la llamada.

FAQ

¿Qué cabecera HTTP gana cuando la misma cabecera aparece dos veces?

HTTP no define un ganador universal para nombres de campo duplicados. Un receptor puede combinar algunos campos, rechazar la solicitud, conservar el primer valor, conservar el último o reenviar ambos. Los campos sensibles para la seguridad necesitan una regla explícita en cada límite.

¿Debe una API aceptar dos cabeceras Authorization?

Trata las cabeceras Authorization duplicadas como un fallo de la solicitud. Elegir la primera o la última hace que la credencial aceptada dependa del comportamiento del cliente y de las reescrituras del proxy, lo que crea un contrato de seguridad deficiente. Rechaza la solicitud antes de autenticar y registra el duplicado de forma segura.

¿HTTP/2 puede crear cabeceras duplicadas?

Pueden hacerlo, y eso es una fuente importante de confusión. HTTP/2 y HTTP/3 transportan los campos de cabecera como bloques estructurados, mientras que un salto HTTP/1.1 puede serializarlos de otra forma. La pasarela debe mantener la regla de rechazo de duplicados al traducir entre protocolos.

¿Los proxies inversos combinan las cabeceras HTTP duplicadas?

Un proxy inverso puede conservar ambos campos, combinarlos, eliminar uno o añadir sus propias credenciales. El resultado depende de su configuración y del orden de los módulos, no del navegador ni del cliente de la API. Prueba la ruta exacta desplegada en lugar de asumir que el proxy es transparente.

¿Puedo enviar Authorization y X-API-Key juntas?

Usa una cabecera distinta solo si el servicio lo documenta explícitamente, como X-API-Key o una cabecera de credenciales específica del proveedor. No la envíes junto con Authorization como mecanismo alternativo. El servidor debe rechazar las solicitudes que presenten credenciales en conflicto, salvo que su documentación defina una elección segura y determinista.

¿Authorization y authorization son cabeceras diferentes?

No. Los nombres de las cabeceras HTTP no distinguen entre mayúsculas y minúsculas, por lo que authorization, Authorization y AUTHORIZATION designan el mismo campo. El detector de duplicados debe comparar nombres normalizados, no su escritura original.

¿Puedo combinar con una coma las cabeceras Authorization duplicadas?

No combines las cabeceras Authorization con una coma. Las comas pueden aparecer dentro de la sintaxis de autenticación, y una cabecera de autenticación normalmente no es un campo de tipo lista. Rechaza la solicitud o elimina el campo no deseado en un límite de confianza, siguiendo una regla documentada.

¿Cómo depuro de forma segura las cabeceras de solicitud duplicadas?

Inspecciona la solicitud sin procesar en cada salto: el cliente, el proxy perimetral, la pasarela de la aplicación y la propia aplicación. Registra nombres de cabecera y metadatos seguros, como longitudes o el esquema de credenciales, pero nunca tokens Bearer. Un listener local sirve para comprobar qué emitió realmente el cliente.

¿Siempre se usa la primera cabecera Authorization?

Evita depender del orden de la solicitud. Las distintas bibliotecas conservan, reordenan, agrupan o sobrescriben los campos repetidos, y los intermediarios pueden cambiar su representación en la red. Una API segura se comporta igual y rechaza todos los duplicados, sin importar el orden.

¿También pueden duplicarse las cabeceras de autenticación personalizadas?

No des por hecho que permanecerá sin cambios. Algunos clientes pueden enviar varias cabeceras personalizadas, otros sobrescriben una entrada de mapa y los intermediarios pueden aplicar su propia normalización. Captura la solicitud en la red durante una prueba aislada y conserva esa prueba en las comprobaciones de lanzamiento.

Sallyport

Sallyport ejecuta llamadas de API y comandos SSH por tu agente de IA. Las claves se quedan en una bóveda local de tu Mac; tú apruebas cada ejecución y cada acción queda en un registro sellado.

© 2026 Sallyport · Código abierto bajo Apache-2.0 · Oleg Sotnikov