Skip to main content

Validación segura de URL en Python

Escrito por

Afzaal Ahmad Zeeshan

feature python linting

4 de noviembre de 2022

0 minutos de lectura

Todo lo que hay en Internet tiene un localizador uniforme de recursos (URL) que lo identifica de forma única y permite que los usuarios de Internet accedan a archivos y otros medios. Por ejemplo, este artículo tiene una URL única que ayuda a los rastreadores de optimización para motores de búsqueda (SEO) a indexarlo para que los usuarios puedan encontrarlo.

La primera definición de la sintaxis de las URL se encuentra en la solicitud de comentarios (RFC) 1738 de 1994. Desde entonces, la estructura de las URL ha pasado por muchas revisiones para mejorar su seguridad. Sin embargo, los desarrolladores suelen no usar la definición de RFC según lo previsto, lo que contribuye a numerosos ataques maliciosos.

Un ejemplo reciente es el exploit de día cero de RCE detectado en Log4j, un popular paquete de registro para Java. Este ataque ocurrió cuando la interfaz de nombres y directorios de Java (JNDI) evaluó una cadena de registro maliciosa. JNDI es una API de Java para un servicio de directorio que permite que los clientes de software Java detecten y busquen datos y recursos (en forma de objetos Java) mediante un nombre. Cuando evalúa una cadena de registro maliciosa, se conecta a un servidor remoto y ejecuta código Java malicioso. Por lo tanto, las empresas deben validar continuamente las URL proporcionadas por agentes externos, como clientes, socios y otros.

Otro ejemplo es el ataque de falsificación de solicitudes del lado del servidor, que puede comprometer un programa de servidor cuando este accede a una URL insegura. Los usuarios maliciosos pueden aprovechar los campos de entrada proporcionados para dañar nuestras soluciones web y, peor aún, la imagen pública de nuestra organización.

En este artículo, exploraremos los desafíos que presentan las URL corruptas, cómo pueden dañar tus aplicaciones y cómo abordar el problema. Para seguir los pasos, asegúrate de tener Python instalado y configurado en tu equipo.

Riesgos de seguridad de las URL

Las URL pueden ser riesgosas, ya que pueden dirigir a los usuarios desde una página web legítima a una maliciosa. También pueden abrir múltiples vectores de ataque, como el scripting entre sitios (XSS), una vulnerabilidad de seguridad presente en algunas aplicaciones web. Esta vulnerabilidad permite que los atacantes inyecten scripts del lado del cliente en páginas web que ven otros usuarios.

Este riesgo de seguridad puede tener consecuencias graves en ciertos sectores, como el bancario. Un cliente desprevenido puede abrir una página que parece auténtica, pero que controla un atacante, porque cree que es la página de inicio de sesión de su aplicación bancaria. Se trata de un tipo de ataque de phishing basado en la ingeniería social, en el que un atacante envía mensajes fraudulentos, falsos o engañosos para convencer a una persona de que revele información confidencial. También podría implementar software malicioso en la infraestructura de la víctima, incluido ransomware. Si el atacante obtiene el nombre de usuario y la contraseña de una persona que usa servicios bancarios, puede usar esa información para iniciar sesión en su cuenta bancaria y causar daños.

Pueden producirse ataques más avanzados con URL debido a la falsificación de solicitudes del lado del servidor. Este ataque ocurre en los servidores que envían solicitudes a las URL proporcionadas por los clientes. Al hacer una solicitud, un atacante puede tomar el control del servidor para realizar acciones no permitidas, como escanear puertos e información de red, solicitar metadatos de la infraestructura, imprimir y mostrar información confidencial, como contraseñas o tokens.

En las siguientes secciones, se muestra cómo validar y sanitizar las URL que no controlas. Por ejemplo, si creamos una plataforma social donde los usuarios pueden comunicarse e intercambiar datos, podemos controlar qué URL se permiten y cuáles podemos ocultar.

Cómo validar URL en Python

Python, un lenguaje de programación, se usa ampliamente para crear aplicaciones y sitios web para millones de clientes en todo el mundo. Aunque Python no tiene un escáner y validador de URL integrado, existen analizadores y validadores de URL para Python desarrollados por la comunidad, que podemos usar para validar nuestras URL y hacerlas más seguras. Algunos frameworks de aplicaciones web también ofrecen escáneres y validadores de URL para desarrollar aplicaciones web.

Validación de URL

Un método popular para validar URL en Python es el paquete de Python validators. Podemos usar el paquete validators para determinar si una URL es válida. Para ser válida, una URL debe:

  • Tener un formato correcto, es decir, cumplir todas las reglas de las especificaciones HTTP o HTTPS

  • Tener un recurso en esa dirección, ya que la URL no es válida si no tiene un recurso asociado

El paquete validators de Python ofrece un método para URL que verifica la URL, comprueba si es segura y busca palabras clave y caracteres no válidos. Si una URL está disponible en el dominio público (es decir, no está detrás de un firewall, un muro de pago u otra barrera de acceso), omite las direcciones IP internas.

Para usar el paquete validators, descarga y configura la dependencia en tu entorno local de Python con pip. Para descargar el paquete validators, ejecuta el siguiente código en tu terminal o interfaz de línea de comandos local:

$ python3 -m pip install validators

Cuando termine de ejecutarse este comando, tendremos el paquete validators en nuestro equipo.

A continuación, crea un archivo de Python llamado main.py y escribe el código de Python para probar una URL:

import validators

validation = validators.url("http:/www.google.com")
if validation:
print("URL is valid")
else:
print("URL is invalid")

Después de agregar este código al archivo main.py, ejecútalo en el intérprete de Python mediante la interfaz de línea de comandos de Python:

$ python main.py

El código muestra "URL is invalid" porque falta el carácter / en la URL después de http:/.

El paquete también puede determinar si una URL es accesible públicamente, lo que resulta útil para validar si el usuario intenta solicitar una dirección IP interna. Agrega el siguiente código al mismo archivo de Python y ejecútalo para intentar validar una URL.

validation = validators.url("https://10.0.0.1", public=True)
if validation:
print("URL is valid")
else:
print("URL is invalid")

Una vez más, el resultado indica que la URL no es válida. Esto se debe a que la URL no está disponible en dominios públicos, aunque no tenga ningún problema en sí. Para obtener más información sobre las funciones del paquete validators, consulta su documentación.

Análisis con expresiones regulares

Otro método que podemos usar para validar URL es utilizar expresiones regulares. Por ejemplo, podemos usar expresiones regulares para exigir que una URL incluya HTTPS antes de validarla. El código para completar esta validación es el siguiente:

^https:\/\/[0-9A-z.]+.[0-9A-z.]+.[a-z]+$

Esta expresión regular coincide con el término https://www.google.com, pero no con http://www.google.com, aunque ambas son URL válidas. Puedes obtener más información sobre las expresiones regulares en este sitio web. Podemos probar la expresión anterior en código de Python:

import re

pattern = "^https:\/\/[0-9A-z.]+.[0-9A-z.]+.[a-z]+$"
result = re.match(pattern, "https://www.google.com")

if result: 
print(result)
else:
print("Invalid URL")

El resultado del código anterior es la URL coincidente. Si modificas la cadena de URL anterior y quitas HTTPS o la cambias a HTTP, obtendrás un objeto None, lo que indica que no se encontró ninguna URL coincidente.

Sin embargo, las expresiones regulares son complicadas y poco prácticas para situaciones reales. Son difíciles de leer y complejas de depurar y escalar. Por eso, las bibliotecas suelen ser una mejor solución.

Para ver un caso de uso más avanzado de una expresión regular que analiza la URL con todas las estructuras y la sintaxis conformes, consulta este hilo de Stack Overflow.

Una ventaja de usar expresiones regulares es que también puedes encontrar URL no válidas dentro de cadenas de entrada. Esto solo es posible con expresiones regulares, no con bibliotecas comunes. El paquete validators no funciona, aunque la cadena tenga espacios en blanco al principio o al final. Para usar el paquete de la mejor manera, debes sanitizar la cadena de entrada y pasarla al paquete validator.

Uso de urllib

Otro paquete que analiza la URL y muestra sus partes es urllib. Podemos usarlo con el intérprete de Python 3.

El siguiente código verifica si una URL es válida:

from urllib.parse import urlparse
result = urlparse("https:/www.google.com")
if result.scheme and result.netloc:
print("Success")
else:
print("Failed")

print(result)

Cuando configuramos el esquema y el campo netloc de la variable result, la URL es válida y se puede usar. De lo contrario, la URL no es válida y debemos tener cuidado.

Identificación de vulnerabilidades comunes

Algunos frameworks de Python, como Django, ofrecen paquetes de validación integrados que nos permiten validar URL dentro del framework. Sin embargo, el desafío de depender de estas bibliotecas es que, aunque conozcamos el framework, debemos asegurarnos de que el paquete en sí sea seguro. Además, el código abierto hace que confiar en el paquete sea más complejo.

Podemos usar una herramienta de seguridad como Snyk Advisor para revisar rápidamente todos los paquetes de código abierto que usamos y los nuevos que queremos implementar, en busca de vulnerabilidades comunes. A partir de esta revisión, Snyk nos proporciona un informe de seguridad que podemos usar para determinar si debemos incluir el paquete. Por ejemplo, podemos usar Snyk Advisor para asegurarnos de que nuestros paquetes, como el paquete validators que usamos en la demostración anterior, sean seguros.

También podemos usar Snyk Open Source junto con Snyk Advisor para detectar problemas de licencias, vulnerabilidades y otros problemas de seguridad que puedan existir en nuestro conjunto de herramientas de código abierto. Además, podemos consultar Snyk Vulnerability Database (VulnDB) para buscar vulnerabilidades conocidas relacionadas con URL, como esta vulnerabilidad en el framework Flask, que redirige a un usuario a una ubicación sin validar la URL. Al consultar esta base de datos, podemos proteger nuestras páginas web y aplicaciones de forma proactiva.

Validación de URL en Python

En este artículo, exploramos los desafíos que las URL no sanitizadas plantean a una aplicación web y cómo sanitizarlas según sea necesario. Comenzamos con validaciones básicas de URL mediante los paquetes validator y urllib. También mostramos cómo usar estos paquetes para confirmar si todas las URL son públicas o si algunas son internas y se usan para atacar la aplicación web. Después, usamos una expresión regular básica para mostrar cómo una sola línea de código puede analizar las URL en busca de información básica obligatoria, como que todas usen HTTPS. También explicamos por qué las expresiones regulares son una forma compleja y difícil de validar las URL.

Por último, vimos cómo elegir bibliotecas de código abierto seguras. Snyk Advisor es una fuente confiable de información al usar paquetes de código abierto. Para obtener más información, consulta la guía de prácticas recomendadas de seguridad para Python, que te ayudará a preparar los pipelines de integración continua y desarrollo continuo (CI/CD) para revisar cualquier vulnerabilidad que se agregue a tu código.

Empieza con los desafíos de Capture the Flag

Aprende a resolver desafíos de captura la bandera con nuestro taller virtual introductorio a pedido.