Tema representativo de entrevista

Entrevista de Go 1.26: ¿Cómo migrar después de que net/url endurece la validación de dos puntos en el host?

GeneralDifícil
Equipo editorial de Offer.ccPublicado Actualizado

Pregunta

Un servicio en Go se actualizó a la versión 1.26 y algunas URLs internas ya no se pueden parsear. Explica por qué net/url rechaza los dos puntos adicionales en un host, distingue IPv6 válida de entradas incorrectas y diseña pruebas, un despliegue canary y una reversión temporal.

Prompt y contexto

Un servicio HTTP en Go se actualizó de 1.25 a 1.26 y descubrió que los valores históricos http://localhost:80:80/ y http://::1/ ahora fallan, mientras que http://[::1]/ sigue funcionando. Explica el cambio de net/url.Parse, su efecto en los proxies y defensas contra SSRF, y una migración que no dependa de un modificador de compatibilidad permanente.

Go 1.26 establece por defecto urlstrictcolons en 1, rechazando los dos puntos adicionales en un subcomponente de host que no se pueden interpretar como host:puerto; este comportamiento se incorporó de forma retroactiva a Go 1.25.2 y 1.24.8. El RFC 3986 define el host como un literal de IP (IP-literal), una dirección IPv4 o un nombre registrado, con el puerto separado por dos puntos, de modo que la dirección IPv6 textual debe ir entre corchetes.

Qué evalúa el entrevistador

  • ¿Puedes explicar a partir de la sintaxis URI por qué los dos puntos adicionales son ambiguos o inválidos?
  • ¿Puedes distinguir entre IPv6 sin corchetes, un [IPv6]:port válido, nombres de host y puertos inválidos?
  • ¿Puedes gestionar la migración de configuraciones, URLs de terceros, reescritura de proxies y registros en lugar de simplemente desactivar la validación?
  • ¿Puedes explicar que GODEBUG=urlstrictcolons=0 es una herramienta de compatibilidad temporal y no una política de validación de entradas?
  • ¿Puedes demostrar el comportamiento de parseo, conexión, redirección y SSRF con pruebas de regresión tras la actualización?

Preguntas para aclarar primero

  • ¿Las URLs que fallan provienen de una configuración manual, una base de datos, entradas de usuarios o un callback de terceros? Sus niveles de confianza difieren.
  • ¿La aplicación combina url.Parse, url.Hostname y url.Port? Distintas APIs de parseo cambian el comportamiento.
  • ¿Se debe admitir IPv6 interna, se requiere un puerto y puede un proxy reescribir el Host?
  • ¿Se pueden corregir los valores antiguos en línea, o se pueden validar y rechazar en un lote previo al despliegue?
  • ¿El servicio utiliza el parseo de URLs para control de acceso, enrutamiento multi-inquilino o defensas SSRF?

Respuesta en 30 segundos

"Clasificaría los fallos por origen y estructura del host. Go 1.26 activa urlstrictcolons por defecto, por lo que las IPv6 sin corchetes y las cadenas con múltiples dos puntos en el host son rechazadas; la forma explícita es [::1], con un puerto escrito como [::1]:8080. Repararía y rechazaría valores erróneos en los límites de configuración, agregaría pruebas de regresión de parseo y de red, y supervisaría la tasa de fallos en un canary. GODEBUG=urlstrictcolons=0 es solo una herramienta de reversión y limpieza a corto plazo, nunca una política permanente para entradas no confiables."

Análisis detallado paso a paso

  1. Establecer una línea base. Recopila muestras con fallos en la versión anterior y en Go 1.26, registrando errores de parseo, valores sin procesar, fuentes y uso final. Que "se pueda parsear" no significa que sea "seguro para conectar"; inspecciona también esquema, nombre de host, puerto y redirecciones.
  1. Clasificar según la sintaxis URI. http://[::1]/ es un literal de IP entre corchetes; http://[::1]:8080/ coloca el puerto después de los corchetes. http://::1/ utiliza dos puntos tanto como datos del host como delimitador de puerto, mientras que http://localhost:80:80/ contiene múltiples delimitadores de puerto; ambos son valores que deben repararse.
  1. Corregir primero los límites de datos. Agrega validación a los archivos de configuración, migraciones de bases de datos y APIs de administración: normaliza IPv6 con corchetes, parsea los puertos como enteros dentro de rango y rechaza hosts no interpretables. Durante una limpieza por lotes, conserva el valor original, el corregido y la fuente propietaria; aísla los registros que no puedan decidirse automáticamente.
  1. Revisar la ruta de seguridad. El control de acceso debe utilizar los resultados parseados de Hostname(), puerto e IP, con límites explícitos para DNS, redirecciones y reescritura de proxies. Nunca clasifiques destinos internos frente a públicos a partir de un prefijo de cadena o de un único resultado de Parse. Vuelve a ejecutar los casos de SSRF, proxy y redirección tras la actualización.
  1. Diseñar una reversión temporal. GODEBUG=urlstrictcolons=0 puede restaurar el comportamiento anterior en un entorno controlado, pero necesita una fecha de caducidad, métricas y alertas, y no debe permitir que nuevas entradas de usuarios eludan la validación. Una opción más segura es habilitarlo únicamente para un conjunto inventariado de configuraciones heredadas en un proceso aislado, y luego desactivarlo tras la limpieza.
  1. Despliegue Canary y verificación. Ejecuta tráfico espejo (shadow traffic) y un conjunto pequeño de instancias, comparando errores de parseo, errores de conexión, coincidencias de proxy y resultados de redirección. Los criterios de paso deben incluir IPv4 válida, IPv6 entre corchetes, IPv6 malformada, dos puntos adicionales, puertos vacíos y redirecciones maliciosas. Expande únicamente después de completar la limpieza del código heredado.
go
func validateEndpoint(raw string) (*url.URL, error) {
    u, err := url.Parse(raw)
    if err != nil {
        return nil, err
    }
    if u.Scheme != "http" && u.Scheme != "https" {
        return nil, fmt.Errorf("unsupported scheme")
    }
    host := u.Hostname()
    if host == "" {
        return nil, fmt.Errorf("missing host")
    }
    if p := u.Port(); p != "" {
        n, err := strconv.Atoi(p)
        if err != nil || n < 1 || n > 65535 {
            return nil, fmt.Errorf("invalid port")
        }
    }
    return u, nil
}

Respuesta modelo

Primero identificaría el origen de cada valor erróneo y separaría los errores de sintaxis de los fallos de conexión. Go 1.26 habilita por defecto urlstrictcolons=1, rechazando http://::1/ y http://localhost:80:80/ porque los dos puntos no pueden interpretarse de forma inequívoca como una IPv6 válida o un único puerto; http://[::1]:8080/ es explícito.

En los límites de configuración y administración, rechazaría los valores malformados, repararía automáticamente los registros comprobados como IPv6 y aislaría los registros ambiguos para sus propietarios. Cada ruta que utilice URLs para enrutamiento, intermediación de proxies o defensa SSRF debe volver a probar el nombre de host, el puerto, DNS, las redirecciones y las reescrituras de proxies. GODEBUG=urlstrictcolons=0 es una reversión de compatibilidad limitada en el tiempo con métricas y alertas, no una forma de permitir que las entradas no confiables eludan la nueva comprobación. El despliegue canary compara errores de parseo, errores de conexión y casos de seguridad antes de retirar la reversión.

Errores comunes

  • Síntoma: Tratar cualquier cadena IPv6 sin corchetes como válida → Por qué falla: Los límites de host y puerto son ambiguos → Solución: Utilizar [IPv6] y colocar el puerto después de ].
  • Síntoma: Establecer GODEBUG=urlstrictcolons=0 permanentemente → Por qué falla: Las entradas erróneas y la ambigüedad heredada persisten → Solución: Establecer una fecha de vencimiento y reparar los datos y los límites de validación primero.
  • Síntoma: Probar solo si url.Parse devuelve un error → Por qué falla: El nombre de host, el puerto, DNS, las redirecciones y los proxies pueden alterar el resultado de seguridad → Solución: Probar la ruta de red completa.
  • Síntoma: Clasificar direcciones privadas a partir de cadenas sin procesar → Por qué falla: La codificación, el parseo, DNS y las redirecciones pueden eludir las reglas basadas en cadenas → Solución: Parsear consistentemente, resolver IPs y volver a aplicar las políticas después de cada redirección.

Preguntas de seguimiento y respuestas

La configuración heredada debe recuperarse hoy mismo. ¿Cómo se controla el riesgo?

Habilita urlstrictcolons=0 solo para un proceso aislado o un conjunto heredado inventariado explícitamente, con una caducidad, restricciones de origen y destino, y una métrica por cada coincidencia. Los nuevos valores seguirán usando una validación estricta; elimina la reversión después de la limpieza.

¿Por qué [::1] es válido mientras que ::1 está desaconsejado?

La autoridad del URI utiliza dos puntos para separar el host y el puerto. Los corchetes hacen explícito el límite entre el literal de IP IPv6 y el puerto. Colocar ::1 directamente en hostport resulta ambiguo, por lo que Go 1.26 lo rechaza.

¿Dónde debe volver a validar un proxy?

El parseo en el punto de entrada es insuficiente. Después de reescribir el Host, seguir una redirección o resolver DNS nuevamente, vuelve a aplicar las políticas de esquema, nombre de host, IP, puerto y red al nuevo destino; no traslades la decisión de la URL inicial a través de un salto.

¿Cómo se demuestra que la actualización no amplió los rechazos indebidamente?

Mantén un corpus fijo de IPv4 válidas, IPv6 entre corchetes, URLs con puertos, hosts malformados con dos puntos extra, hosts vacíos, puertos inválidos y redirecciones. Ejecútalo en Go 1.24.8, 1.25.2 y 1.26, y luego compara las tasas de fallo de configuraciones reales durante el canary.

Referencias

  • Notas de lanzamiento de Go 1.26
  • Go, compatibilidad con versiones anteriores y GODEBUG
  • RFC 3986 Identificador Uniforme de Recursos: Sintaxis Genérica
  • Código fuente de Go net/url

Lista de verificación para la entrevista

Explica primero el host, los corchetes de IPv6 y el límite del puerto. Luego aborda la limpieza de datos, la validación estricta en los límites, la reevaluación de rutas SSRF y una reversión temporal mediante GODEBUG con caducidad. Mantén la compatibilidad de parseo separada de la seguridad de acceso.

Conclusión en una sola frase

Go 1.26 exige que los servicios conviertan URLs ambiguas en URIs explícitas y utilicen pruebas, un canary y una reversión limitada en el tiempo para lograr una migración segura.

Fuentes públicas

Preguntas relacionadas