Validación de redirecciones HTTP para solicitudes autenticadas de agentes
La validación de redirecciones HTTP evita que las credenciales de API de los agentes crucen destinos no aprobados, métodos inseguros, trucos de DNS y rutas ocultas de SSRF.

La validación de redirecciones HTTP debe realizarse antes de que un agente reenvíe credenciales a la siguiente URL. Una redirección no es una continuación inofensiva de la misma solicitud. Es una instrucción de un servidor remoto para realizar otra solicitud, a menudo a una autoridad, un método y un destino de red diferentes.
Esta diferencia se pierde cuando alguien conecta un agente a un cliente de API y deja activada la opción de redirección predeterminada del cliente. El agente envía una solicitud a una API aprobada. La API responde con 302 Location: https://somewhere-else/.... El cliente la sigue. Si la autenticación se añade demasiado pronto, un atacante que controle el primer endpoint, un parámetro de redirección o una dependencia comprometida puede convertir una llamada permitida en un servicio de entrega de credenciales.
He visto que esto se descarta porque las bibliotecas HTTP maduras suelen eliminar Authorization cuando cambia el host. Esa protección ayuda, pero no es universal ni suficiente. No dice nada sobre cabeceras de credenciales personalizadas, parámetros de consulta firmados, cookies, cuerpos de solicitudes redirigidas, cambios de DNS ni redirecciones al mismo host que conduzcan a un endpoint peligroso. Construye una decisión de redirección explícita en lugar de tratar los valores predeterminados de la biblioteca como tu política.
Las redirecciones crean una nueva decisión de autorización
Cada salto de redirección necesita el mismo análisis que la primera URL porque el servidor elige el siguiente destino. El cliente solicitó un recurso y recibió una respuesta que propone otro URI en el campo Location. La decisión de permitir la URL original no cubre automáticamente el URI propuesto.
RFC 9110 define las redirecciones mediante sus códigos de estado e indica a los agentes de usuario cómo pueden o deben reaccionar. No dice que una credencial de API incluida en la solicitud inicial esté autorizada para todos los URI que un servidor pueda devolver. Esa decisión corresponde a quien realiza la llamada. En una puerta de enlace para agentes, quien realiza la llamada es responsable de decidir qué acciones posteriores ejecutará.
Mantén estos dos eventos separados en el código y en los registros:
- El servidor envía una respuesta de redirección para una solicitud ya realizada.
- El cliente decide emitir una nueva solicitud al destino resuelto.
El primer evento es un hecho. El segundo es una acción privilegiada. Si tu implementación los combina dentro de una llamada de conveniencia como client.Do(request) con las redirecciones automáticas activadas, has ocultado el momento en que debe ejecutarse la política.
Una redirección puede cruzar varios límites a la vez. https://api.example.test/v1/export podría apuntar a https://downloads.example.test/file, que después apunta a una URL de objeto con tiempo limitado en un proveedor de almacenamiento. La cadena puede ser legítima. También significa que una regla imprecisa como «el primer host está aprobado» casi no dice nada sobre la conexión final.
Las redirecciones relativas necesitan el mismo cuidado. Resuelve Location: ../admin contra la URL que la produjo usando un analizador de URL conforme a los estándares. No concatentes cadenas. Una ruta que comienza por // es relativa al esquema y puede cambiar el host. Los delimitadores codificados y formas inusuales, como un valor Location vacío, han provocado suficientes inconsistencias entre clientes como para que una puerta de enlace deba rechazar la ambigüedad en lugar de adivinar.
Inyecta credenciales solo después de validar el destino
El orden seguro es sencillo: recibe la respuesta, analiza el destino candidato, valídalo, construye la siguiente solicitud y después inyecta únicamente las credenciales aprobadas para ese destino. La inyección de credenciales debe producirse en el punto de envío final, no en un objeto de solicitud mutable que sobreviva a una cadena de redirecciones.
Este es el error de diseño que provoca la mayoría de las filtraciones. Un envoltorio construye una solicitud con Authorization: Bearer ..., la envía y permite que el cliente HTTP clone o repita la solicitud después de una redirección. El envoltorio puede tener la intención de usar el token con un único host, pero ya no controla cada envío.
Usa una descripción de solicitud que no contenga secretos. Puede incluir el método, el cuerpo, la referencia a la credencial permitida y la URL inicial. Para cada salto, crea una nueva solicitud de red después de la validación. La capa de envío busca la credencial solo cuando dispone de un destino permitido.
Un modelo compacto sería este:
request intent:
method: POST
initial URL: https://api.acme.test/v1/reports
credential reference: billing-api-prod
body digest: sha256:...
for each response:
if status is not a supported redirect: return response
target = resolve(response.request_url, response.headers["Location"])
decision = validate(target, request intent, response.status)
if decision is reject: record rejection and stop
next_request = build(decision.method, target, permitted body)
inject(credential reference, target, next_request)
send(next_request)
El detalle importante no es el pseudocódigo. Es la vida útil del secreto. El token existe únicamente en la solicitud que ya ha pasado la validación del destino. Nunca permanece en un objeto genérico que una función de redirección pueda reenviar por accidente.
Este orden también permite aplicar el alcance de las credenciales. Un token bearer para api.acme.test no debería autenticar automáticamente uploads.acme.test, aunque ambos nombres pertenezcan a la misma empresa. Asigna a cada regla de destino una referencia de credencial explícita. Si dos servicios comparten deliberadamente una credencial, documenta esa relación en la regla en lugar de inferirla a partir de un sufijo DNS.
La coincidencia de origen evita una filtración, pero no todas
Una coincidencia estricta de origen bloquea los cambios de host evidentes, pero no resuelve por sí sola si una solicitud redirigida es segura. Un origen consta de esquema, host y puerto. Trata los cambios en cualquiera de esos campos como un límite, salvo que exista una excepción explícita.
El esquema importa. Una redirección de HTTPS a HTTP puede exponer cabeceras o el contenido de la solicitud en la red. Rechaza las degradaciones para el tráfico autenticado. Una redirección de HTTP a HTTPS puede parecer segura, pero también cambia la autoridad y puede ocultar un endpoint inesperado. Valídala con normalidad.
El puerto también importa. https://api.example.test y https://api.example.test:8443 son orígenes diferentes. Los desarrolladores suelen olvidarlo porque los navegadores ocultan los puertos predeterminados y los entornos de prueba locales usan puertos alternativos constantemente. Un token destinado a la API pública podría acabar en un servicio de administración si tu regla solo comprueba el nombre de host.
La ruta importa cuando un host de API sirve a aplicaciones no relacionadas. Una redirección de /v1/files a /internal/debug/export permanece en el mismo origen, pero podría exponer un cuerpo o provocar un cambio de estado inseguro. No uses una lista de rutas permitidas como sustituto de la autorización de la aplicación, pero limita los destinos de redirección a los prefijos de API que tu integración realmente necesita.
Los parámetros de consulta requieren un tratamiento especial. Un destino redirigido puede incluir una URL prefirmada, un parámetro de estado o un token de descarga de un solo uso. En la práctica, estos valores son credenciales, aunque no utilicen una cabecera Authorization. No copies los parámetros de consulta de la solicitud anterior a la nueva URL. Usa exactamente el destino redirigido analizado, después de aplicar cualquier regla que prohíba campos userinfo, fragmentos o parámetros que parezcan credenciales.
Un punto de partida práctico es permitir redirecciones del mismo origen únicamente si el esquema sigue siendo HTTPS, el puerto continúa aprobado, la ruta de destino está dentro de la superficie de API permitida por la integración y el estado de redirección permite el método previsto. Trata las redirecciones entre orígenes como una clase separada, con reglas de destino identificadas por nombre.
Los códigos de estado de redirección cambian la solicitud que podrías enviar
Los códigos de estado de redirección tienen semánticas de método, y un cliente que las ignore puede convertir una lectura segura en una escritura inesperada o repetir un cuerpo sensible. No reduzcas toda respuesta 3xx a «seguir Location».
RFC 9110 indica que 307 y 308 conservan el método y el contenido de la solicitud. Si la solicitud original era un POST que contenía la definición de un informe, un 307 o 308 pide al cliente que envíe ese mismo POST y su cuerpo al nuevo destino. Este es el caso de mayor riesgo porque el nuevo host puede recibir tanto datos de negocio como una solicitud con efectos secundarios.
El estado 303 dirige al cliente a recuperar una representación mediante GET o HEAD, independientemente del método original. Suele aparecer después de un envío similar al de un formulario. Para una acción de agente, permítelo solo si el destino del GET redirigido está aprobado por separado y tu integración espera ese patrón. Un 303 no debe heredar una cabecera de autorización solo porque el POST inicial la tuviera.
Los problemas históricos son 301 y 302. RFC 9110 describe la práctica tradicional de cambiar POST a GET para estas respuestas, mientras que 307 y 308 existen para los clientes que deben conservar los métodos. Las bibliotecas varían en los detalles, especialmente con métodos que no son POST y con los cuerpos. Nunca dejes que esta ambigüedad decida qué enviará un cliente autónomo.
Define el comportamiento por escrito. Por ejemplo:
- Sigue 301 y 302 únicamente para solicitudes
GETyHEAD. - Sigue 303 solo emitiendo un
GEToHEADsin credenciales, y valida de nuevo ese destino antes de añadir cualquier credencial de lectura aprobada. - Sigue 307 y 308 únicamente cuando la regla de destino permita explícitamente el método original y la clase de cuerpo.
- Rechaza una redirección después de un método no idempotente como
POST,PATCHoDELETE, salvo que la integración tenga un flujo de redirección documentado.
Esto puede romper una API mal diseñada. Es preferible a repetir silenciosamente una instrucción de pago, una carga de código fuente o un comando administrativo en un lugar elegido por un servidor remoto. Si un proveedor exige escrituras redirigidas, añade una excepción de alcance muy limitado y prueba la secuencia exacta.
Las reglas de destino necesitan campos, no una cadena de host
Un validador de redirecciones útil evalúa el destino frente a una regla con suficiente detalle para describir el servicio que pretendías llamar. Una lista de hosts permitidos resulta atractiva porque es corta. También es el punto donde se acumulan excepciones hasta que nadie puede explicar qué puede enviar un agente y a dónde.
Para cada destino de redirección permitido, decide lo siguiente:
- Qué esquemas están permitidos, normalmente solo HTTPS.
- Qué nombres de host y puertos normalizados están permitidos.
- Qué métodos y prefijos de ruta puede usar la solicitud redirigida.
- Qué referencia de credencial, si existe, puede inyectarse allí.
- Si el destino puede resolverse en direcciones de red privadas o locales.
Normaliza antes de comparar. Convierte los nombres de host DNS a minúsculas, elimina de forma coherente el punto final, analiza correctamente los literales IPv6 entre corchetes y rechaza una codificación porcentual mal formada. Nunca compares cadenas de URL sin analizar. https://[email protected]/ tiene evil.test como host, aunque contenga un nombre de confianza antes del signo @.
No uses endsWith("example.test") como comprobación de autoridad. Acepta notexample.test. Incluso una regla de sufijo con delimitador como *.example.test necesita una revisión de propiedad. Los subdominios comodín suelen incluir sistemas de vista previa, nombres controlados por clientes, redireccionadores o infraestructura administrada por otro equipo.
El validador debería devolver una decisión razonada, no un booleano. Los operadores necesitan saber si rechazó una degradación de esquema, un puerto no aprobado, un método no permitido, una dirección privada o un límite de redirecciones agotado. Esta información pertenece al registro de acciones, con los valores de los tokens eliminados.
Establece un límite de redirecciones pequeño y fijo. El límite detiene los bucles y hace visible una cadena larga. No aceptes un número proporcionado por el agente. La puerta de enlace controla este límite porque controla las acciones de red.
Un flujo de descarga habitual puede filtrar una solicitud privilegiada
Los casos peligrosos rara vez llegan etiquetados como ataques. A menudo parecen endpoints prácticos y normales que aceptan una URL o devuelven una ubicación de descarga.
Imagina que un agente recibe la orden de obtener un informe de una API de facturación aprobada. El agente envía POST /v1/exports con un token bearer. La API devuelve un 303 a una URL de descarga. La puerta de enlace lo sigue automáticamente y conserva el token porque su inyector de cabeceras personalizadas se ejecuta antes del enlace de redirección de la biblioteca HTTP.
Al principio, el host de descarga es otro servicio gestionado por el mismo equipo. Meses después, un cambio de configuración hace que el endpoint de exportación acepte un parámetro destination para que los clientes puedan usar un proveedor de almacenamiento. Un atacante con acceso a los parámetros del informe proporciona una URL bajo su control. La API aprobada devuelve una redirección a esa URL. La biblioteca HTTP la trata como un 303 normal y la puerta de enlace ya ha añadido X-Service-Token.
No ocurrió nada extraordinario. La primera solicitud a la API estaba permitida, la sintaxis de redirección era válida y el token nunca apareció en un prompt del agente. El fallo se produjo porque las credenciales se asignaron antes de conocer el destino.
Una implementación correcta registra el 303, resuelve el destino, reconoce que el host no tiene una regla de destino y se detiene. El operador ve una redirección rechazada en lugar de una llamada saliente misteriosa. Si el servicio de descarga previsto necesita acceso, crea una regla independiente para su host exacto y utiliza una credencial de descarga que no pueda llamar a la API de facturación.
Los agentes añaden otra vía a este fallo. Un agente puede influir en una URL mediante el texto de una incidencia, un archivo de configuración de un repositorio, un campo de respuesta de una API o una instrucción procedente de una herramienta. No supongas que una URL proviene de un desarrollador solo porque aparece dentro de una solicitud creada por tu agente. Los datos pueden convertirse rápidamente en entradas de enrutamiento.
Las comprobaciones de DNS deben producirse en el momento de la conexión
Validar el nombre de host por sí solo no detiene la falsificación de solicitudes del lado del servidor. Un host puede resolver a una dirección pública durante la revisión y a una dirección de bucle local, de enlace local o privada cuando el cliente se conecta. El tratamiento de redirecciones ofrece a un atacante oportunidades repetidas para explotar esa diferencia.
Resuelve cada host aprobado cerca del momento de la conexión y evalúa todas las direcciones devueltas según tus reglas de red. Rechaza rangos de bucle local, direcciones no especificadas, rangos de enlace local, rangos privados, direcciones multicast y sus equivalentes IPv6, salvo que una regla las permita explícitamente. Aplica el mismo tratamiento a las direcciones IP literales en las URL de redirección.
No resuelvas un host una vez, apruebes una dirección y dejes que otra pila HTTP vuelva a resolverlo. Eso crea una brecha entre la comprobación y el uso. La conexión debe utilizar el conjunto de direcciones que evaluaste, o el transporte debe ofrecer una forma fiable de confirmar la dirección del par y rechazar una discrepancia. Esto es más difícil de lo que parece cuando intervienen grupos de conexiones, proxies y DNS de doble pila.
Las implementaciones con proxies corporativos necesitan un modelo de excepciones definido. Si la puerta de enlace se conecta únicamente a un proxy explícito, valida el proxy como par de red y conserva las reglas de destino de la aplicación antes de formar la solicitud al proxy. No declares seguros todos los rangos privados solo porque una organización use direcciones privadas para sus servicios. Nombra los hosts y puertos internos que el agente necesita.
El DNS rebinding es una de las razones por las que una regla de redirección no puede ser una aprobación permanente de un host. El comportamiento de la caché, los TTL y las diferencias entre resolutores pueden cambiar la respuesta. Toma la decisión para la conexión que estás a punto de realizar y registra la dirección del par seleccionada sin tratarla como prueba de que el destino de la aplicación estaba autorizado.
Las cookies, las URL firmadas y los cuerpos también son credenciales
Los equipos suelen proteger Authorization y dejar intacto el resto del material saliente. Una redirección puede filtrar credenciales o datos sensibles por varios canales adicionales.
Las cookies tienen reglas de dominio y ruta, pero una puerta de enlace para agentes no debería depender de un almacén de cookies general al estilo de un navegador para las credenciales de máquina. Mantén las cookies desactivadas por defecto en las llamadas privilegiadas. Si una integración las necesita, limita el almacén a esa integración y vuelve a evaluar la inclusión de cookies para cada destino de redirección.
Las URL prefirmadas colocan deliberadamente la autorización en la cadena de consulta. Normalmente deberían funcionar sin añadir ningún otro token de servicio. Si una regla de destino reconoce una URL de almacenamiento prefirmada, envíala exactamente con el material de autorización que ya contiene y con un método restringido, normalmente GET o PUT. No añadas tus cabeceras estándar por costumbre.
Los cuerpos de las solicitudes también contienen secretos. Un cuerpo JSON puede incluir un archivo de origen, datos de clientes o una aserción firmada opaca. Para 307 y 308, exige una regla explícita que permita repetir el cuerpo en ese servicio concreto. Para los demás códigos de redirección, no transformes ni vuelvas a enviar el cuerpo silenciosamente. La comodidad de una biblioteca no justifica duplicar contenido sensible.
El encabezado HTTP Referer puede revelar rutas y valores de consulta cuando un cliente lo añade. Los clientes de API deberían evitar, por lo general, conservar una cabecera Referer al atravesar redirecciones. Del mismo modo, elimina las cabeceras que describan la ruta interna original, la sesión del agente o la identidad del usuario, salvo que la regla de destino las necesite explícitamente.
Clasifica las cabeceras en tres grupos: cabeceras que siempre pueden regenerarse, cabeceras permitidas únicamente para un destino identificado y cabeceras que nunca deben cruzar una redirección. Esto es más fiable que mantener una lista imprecisa de «cabeceras sensibles». Content-Type puede ser inofensivo para una carga permitida; X-Internal-Actor puede identificar a una persona que nunca autorizó el siguiente host.
Audita la cadena como una acción con varios saltos
Un registro de auditoría debe mostrar la cadena de redirección sin exponer el material que hizo privilegiada la solicitud. La URL final y el código de estado no bastan. Ocultan si el cliente cruzó un origen, cambió de método, eliminó la autenticación o rechazó un destino sospechoso antes de conectarse.
Registra la intención de la solicitud inicial, cada estado de respuesta, cada valor de Location sin secretos después de aplicar la redacción, el destino resuelto, el resultado de la política, el método seleccionado y la clase de credencial utilizada en ese salto. Registra un identificador estable de la credencial, nunca un token, una contraseña o una URL firmada completa. Aplicar un hash a una URL completa puede ayudar a correlacionarla, pero no confundas un hash con una redacción segura cuando la entrada tiene poca entropía.
Vincula todos los saltos a un único identificador de acción principal. Así, un investigador puede distinguir entre «el agente solicitó una exportación» y «la puerta de enlace realizó cuatro llamadas de red para completar la exportación». Esto también permite a un operador revocar una sesión activa cuando la cadena empieza a comportarse de forma inesperada.
Un registro resistente a manipulaciones aporta pruebas útiles después de los hechos, pero no detiene una redirección insegura. La prevención debe estar en la ruta de reenvío. Sallyport registra las sesiones de los agentes y las llamadas individuales en un único registro de auditoría cifrado y encadenado mediante hashes, de modo que los registros de acciones conscientes de las redirecciones puedan conservar la secuencia de decisiones en lugar de reducir la cadena a un resultado final.
Prueba el registro con casos rechazados deliberadamente. Provoca un 302 entre orígenes, una redirección de HTTPS a HTTP, un 307 después de un POST, un campo Location mal formado y un destino que resuelva a una dirección de bucle local. Si esos registros no indican al revisor por qué se detuvo la puerta de enlace, mejora el esquema de eventos antes de que un incidente te obligue a hacerlo.
Haz que el comportamiento de las redirecciones forme parte del contrato de la herramienta
Una herramienta que llama a una API HTTP debe indicar a sus usuarios si sigue redirecciones y bajo qué condiciones. «Usa HTTP estándar» no es un contrato. El comportamiento varía entre bibliotecas y cambia cuando alguien sustituye un cliente, añade un proxy o mueve la autenticación a un middleware.
Escribe pruebas contra un dispositivo local de redirecciones con endpoints distintos. El dispositivo debe devolver códigos de estado y valores Location controlados, y capturar el método entrante, el resumen del cuerpo, el host y las cabeceras. Tus aserciones deben demostrar que un destino no aprobado no recibe ninguna cabecera de credencial, que un 303 no repite el cuerpo de un POST y que un 307 permitido envía únicamente las cabeceras y el cuerpo autorizados por la regla.
No permitas que el agente seleccione una política de redirección en los argumentos de la herramienta. Un agente puede solicitar una integración conocida y proporcionar parámetros de solicitud normales. La puerta de enlace decide si esa integración puede seguir redirecciones, cuántos saltos permite y qué credenciales puede utilizar. Esta separación evita que una inyección en un prompt se convierta en follow_redirects=true.
Para una primera implementación, elige un contrato deliberadamente limitado: sigue redirecciones HTTPS aprobadas únicamente para GET y HEAD, inyecta las credenciales por destino después de la validación y rechaza toda escritura redirigida. Añade excepciones solo después de poder explicar el flujo del proveedor, el límite de destino, el comportamiento del método y el registro de auditoría. Unas pocas negativas explícitas molestarán a los desarrolladores. Un token enviado a un atacante molestará mucho más a todo el mundo.
FAQ
¿Un cliente HTTP debería seguir automáticamente las redirecciones cuando usa credenciales de API?
No. Una respuesta de redirección pide al cliente que realice otra solicitud a una URL nueva. Trata esa siguiente solicitud como una decisión de autorización independiente, especialmente si va a llevar un token bearer, una credencial de cliente, una cabecera de autenticación personalizada o datos de inicio relacionados con SSH.
¿Una redirección al mismo origen siempre es segura?
Una redirección del mismo origen mantiene sin cambios el esquema, el nombre de host y el puerto. Aun así, necesita validación porque pueden cambiar el método, la ruta, la cadena de consulta, la IP de destino y el número de redirecciones. El mismo origen es una condición útil, no una política de seguridad completa.
¿Las bibliotecas HTTP eliminan Authorization en las redirecciones entre dominios?
Muchas bibliotecas HTTP eliminan la cabecera de autorización estándar cuando cambia el host, pero no puedes tratar ese comportamiento como un límite de seguridad. Las cabeceras personalizadas, las cookies, las URL firmadas, los cuerpos de las solicitudes y las credenciales inyectadas por debajo de la biblioteca todavía pueden cruzar el límite si tu código de reenvío no lo impide.
¿Qué debe ocurrir cuando un destino de redirección no está aprobado?
Rechaza la redirección si el destino no cumple tus reglas de destino. Registra la URL original, el código de estado, el valor de Location, el destino analizado y el motivo del rechazo para que un operador pueda determinar si la redirección fue accidental, maliciosa o producto de un error de configuración del servicio.
¿Qué códigos de redirección HTTP son seguros para solicitudes POST?
Ninguno por defecto. Los estados 301, 302, 303, 307 y 308 tienen semánticas de método distintas, y los clientes mantienen comportamientos históricos de compatibilidad con las solicitudes POST. Un cliente con credenciales debe definir sus propias reglas de método en lugar de depender de lo que haga su biblioteca HTTP.
¿Se debería permitir que los agentes sigan redirecciones hacia direcciones IP privadas?
Por lo general, no. Las redirecciones que conducen a direcciones privadas, de bucle local, de enlace local o a servicios locales similares a Unix crean rutas de SSRF. Resuelve y evalúa cada conexión de destino, y aplica excepciones explícitas solo a la infraestructura que administras deliberadamente.
¿Qué nivel de precisión debe tener una lista de permitidos para redirecciones de API?
Una lista de permitidos debe identificar el límite exacto del servicio: esquema, nombre de host, puerto y, a menudo, un prefijo de ruta. Una coincidencia de sufijo como *.example.com puede ser demasiado amplia cuando bajo ese dominio existen equipos no relacionados, subdominios controlados por clientes o servicios de redirección.
¿La aprobación de un usuario puede hacer aceptable una redirección insegura?
No. Una aprobación indica que una persona aceptó una acción en un momento concreto, pero no convierte en seguro un destino posterior que no se haya inspeccionado. Muestra el destino final o redirigido cuando sea posible y exige una nueva aprobación cuando la redirección cruce un límite importante.
¿Qué debe registrar una auditoría de redirecciones HTTP?
El registro debe conservar cada salto en orden: URL de la solicitud, estado de la respuesta, cabecera Location, destino resuelto, método utilizado, clase de credencial y resultado final. Oculta los valores secretos, pero conserva una referencia estable de la credencial para que los investigadores sepan qué ruta de autorización se solicitó.
¿Qué comprobaciones de redirección debe realizar una puerta de enlace para agentes de IA?
Rechaza valores Location mal formados, esquemas no compatibles, un número excesivo de saltos, URL que contengan credenciales y destinos fuera del conjunto aprobado. Hazlo antes de inyectar credenciales o abrir una conexión con el siguiente host.