Idioma : en | de | fr | es
Volver a los blogs
siguiente publicación ▶
%20 en la URL: qué significa y por qué aparece en las direcciones web

Codificación doble en URLs

La codificación doble en URLs ocurre cuando los caracteres ya codificados se codifican una vez más. En lugar de %20 para un espacio, se puede terminar con %2520, porque el propio signo de porcentaje se codificó en %25. Este problema parece pequeño en los logs, pero rompe las redirecciones, los parámetros de API, las rutas de archivo, las firmas y los filtros de seguridad.

El tema importa porque la codificación de URLs generalmente se maneja en varias capas a la vez: navegador, biblioteca de cliente, proxy, framework, enrutador y código de la aplicación. Si dos capas deciden ambas «ayudar», la URL final cambia de significado. En producción, esto a menudo aparece como una URL de callback defectuosa, un flujo OAuth fallido, un archivo que falta o una ruta que funciona en staging pero no detrás de un gateway.

Por qué aparecen URLs doblemente codificadas en sistemas reales

Una URL debería codificarse en la etapa correcta y solo para la parte relevante. Los problemas comienzan cuando los desarrolladores codifican la cadena completa manualmente y luego la pasan a una herramienta que la codifica de nuevo.

Las causas comunes incluyen:

  • codificar un parámetro de consulta antes de darlo a URLSearchParams
  • codificar una URL de redirección completa y luego embebida dentro de otra URL
  • middleware de framework reescribiendo valores ya procesados
  • código frontend enviando entrada codificada a un backend que la codifica de nuevo
  • reglas de proxy o WAF transformando componentes de la solicitud inesperadamente

Un ejemplo visual sencillo

Supongamos que el valor original es:

/docs/My File.pdf

Codificación única correcta para un fragmento de ruta:

/docs/My%20File.pdf

Después de un segundo paso, se convierte en:

/docs/My%2520File.pdf

El servidor puede ahora buscar un archivo que literalmente contiene %20 en su nombre en lugar de un espacio.

Cómo luce el problema de la codificación doble de URL

La parte más difícil es que la URL todavía parece «codificada», por lo que los equipos depuran primero la capa equivocada. Los síntomas dependen del contexto.

Síntomas típicos en producción

Síntoma

Lo que se ve

Causa probable

Redirección rota

El usuario llega a página de error o ruta equivocada

Destino de redirección codificado dos veces

Consulta API inválida

El backend recibe un valor de filtro distorsionado

Cliente y servidor codifican ambos

No coincidencia de firma

La verificación de HMAC o URL firmada falla

La codificación se modificó después de firmar

Archivo o activo faltante

La ruta se resuelve incorrectamente

El segmento de ruta codificado se volvió a codificar

Omisión de regla de seguridad o falso positivo

El filtro se comporta de manera inconsistente

Diferentes etapas de decodificación entre capas

Por qué las URLs anidadas son arriesgadas

Una trampa clásica aparece con las URLs de retorno:

https://app.example.com/login?next=https://site.example.com/account?tab=settings

Si la URL interna debe convertirse en un valor de parámetro, debería codificarse correctamente una sola vez. Pero muchas apps primero la codifican a mano, luego un enrutador o cliente HTTP la codifica de nuevo. Eso crea flujos de callback malformados y logs difíciles de leer.

Errores de codificación doble que cometen los desarrolladores

El error más común es no entender qué API espera datos en bruto y cuál espera datos codificados. Las buenas bibliotecas generalmente quieren valores sin codificar y manejan el escape internamente.

Ejemplo en JavaScript

Incorrecto:

const next = encodeURIComponent("https://site.example.com/account?tab=settings");

const url = "/login?next=" + encodeURIComponent(next);

Esto produce un valor transformado dos veces.

Mejor:

const next = "https://site.example.com/account?tab=settings";

const url = "/login?next=" + encodeURIComponent(next);

Ejemplo con constructores de consultas

Patrón incorrecto:

  • codificar manualmente name=John Doe
  • pasar el resultado a un constructor de consultas
  • el constructor de consultas codifica % de nuevo

Patrón correcto:

  • pasar John Doe en bruto
  • dejar que una capa de confianza construya la cadena de consulta final

Cómo decodificar URLs con doble codificación de forma segura

La decodificación es fácil solo cuando se sabe cuántas veces se transformó el valor. La decodificación repetida a ciegas es peligrosa, especialmente en código sensible a la seguridad, porque puede alterar literales intencionados o ayudar a las cargas útiles a eludir la validación.

Enfoque práctico de decodificación

  1. Inspeccionar el valor de solicitud en bruto desde logs o un proxy de depuración.
  2. Decodificar una vez y comparar el resultado.
  3. Si quedan secuencias de porcentaje donde debería haber caracteres simples, inspeccionar si una segunda decodificación está justificada.
  4. Normalizar solo en un límite controlado.
  5. Validar después de la normalización, no antes.

Ejemplo:

Original: hello%2520world

Decodificar una vez: hello%20world

Decodificar dos veces: hello world

Eso muestra un valor codificado dos veces. Pero no convertir esto en una regla ciega de «decodificar dos veces» para cada solicitud.

Lista de verificación de depuración más segura

  • capturar la URL en bruto exacta
  • separar ruta, consulta y fragmento
  • probar un paso de decodificación a la vez
  • verificar qué capa realizó cada transformación
  • confirmar si el valor debía mantenerse codificado

Prevenir la codificación doble de URL por diseño

La mejor solución es la disciplina arquitectónica, no los parches.

Reglas que funcionan en la práctica

  • codificar en el límite donde se ensambla la URL final
  • mantener los valores internos en bruto tanto tiempo como sea posible
  • nunca codificar manualmente antes de pasar datos a un constructor de URL de confianza
  • no decodificar y volver a codificar sin una razón específica
  • documentar si los auxiliares esperan entrada en bruto o codificada
  • firmar las URLs solo después de que la forma canónica final esté lista

Buena convención de equipo

Elegir un lugar responsable de la transformación de URL:

  • enrutador frontend
  • auxiliar de URL del backend
  • biblioteca de cliente de API
  • capa de normalización del gateway

Una vez que la responsabilidad está clara, el escape duplicado disminuye drásticamente.

Casos límite de codificación doble en parámetros anidados

Algunos casos parecen errores pero en realidad son intencionales. Por ejemplo, si una URL está embebida dentro de otra como dato, la codificación debe preservar separadores como ?, = y & dentro del valor anidado. La clave es que la URL anidada debería codificarse una vez para su papel como valor de parámetro, no repetidamente en cada salto.

Ejemplo: parámetro de redirección

/auth?return_to=https%3A%2F%2Fapp.example.com%2Fdashboard%3Fpage%3D2

Esto es normal. Se convierte en un problema solo si el mismo valor luego se transforma en:

/auth?return_to=https%253A%252F%252Fapp.example.com%252Fdashboard%253Fpage%253D2

Esa segunda versión generalmente indica procesamiento adicional.

Manejo de valores ya transformados en APIs y middleware

Las pilas de framework a menudo mezclan el manejo automático y manual. Un proxy inverso puede normalizar una vez, el framework puede decodificar en parámetros de ruta, y el middleware personalizado puede aplicar otro paso. El resultado es inconsistencia entre logs, entrada del handler y llamadas a servicios posteriores.

Dónde auditar primero

  • reglas de reescritura del proxy inverso
  • configuración de normalización de CDN o WAF
  • extracción de parámetros de ruta
  • auxiliares de redirección
  • constructores de solicitudes de SDK de terceros
  • filtros de seguridad personalizados

Una auditoría breve en estas capas generalmente revela por qué un valor cambió más de lo esperado.

Conclusión

La codificación doble rara vez es un misterio de bajo nivel. Generalmente es un fallo de coordinación entre capas que todas intentan ayudar con la misma URL. La solución es tratar la codificación como un paso de responsabilidad única, mantener los valores internamente en bruto y normalizar cuidadosamente en el borde.

Cuando una URL parece incorrecta, no limitarse a parchearla con decodificación adicional. Rastrear la ruta completa del valor: dónde comenzó, quién lo codificó, quién lo volvió a codificar y si el componente final era una ruta, un valor de consulta o una URL anidada. Ese enfoque resuelve el error sin crear un sistema más frágil.