Analizar un enlace sospechoso: comprueba si un link de SMS o correo es falso sin abrirlo

¿Te llegó un SMS «de tu banco», un aviso de paquetería o un correo del SAT con un enlace? Pégalo aquí antes de abrirlo. La herramienta revisa el texto del enlace, sin visitarlo, y te explica las señales de fraude que encuentra: dominios que imitan a una marca, letras de otros alfabetos que se ven iguales, direcciones IP, acortadores, redirecciones y descargas de aplicaciones. Todo se analiza en tu navegador: el enlace no se envía a ningún sitio.

Ejemplos:

Esta revisión no visita el enlace, así que no puede saber qué hay en la página: solo mira cómo está escrita la dirección. Un resultado sin señales no garantiza que sea seguro, y uno con señales no prueba que sea un fraude. Ante la duda, no abras el enlace: entra tú mismo en la página del banco o servicio escribiendo su dirección, o llama al número que aparece en tu tarjeta.

Cómo leer un enlace

Lo que importa de una dirección es el dominio registrable: el nombre que alguien compró, justo antes de la terminación (.com, .mx, .com.mx, .gob.mx…). Todo lo que va delante son subdominios, que el dueño del dominio puede llamar como quiera.

  • https://www.bbva.mx/personas: el dominio es bbva.mx, el oficial de BBVA México.
  • https://bbva.mx.verificacion-cuenta.top/acceso: empieza por «bbva.mx», pero el dominio es verificacion-cuenta.top. «bbva.mx» es solo un subdominio inventado.
  • https://sat.gob.mx@192.168.10.5/pago: lo que va antes de la @ se ignora. El navegador va a la dirección IP 192.168.10.5, no al SAT.

En el móvil, los mensajes muestran solo el principio de la dirección. Por eso los enlaces falsos ponen el nombre de la marca al principio y esconden el dominio real al final.

Las señales que revisa

  • Marca en un dominio ajeno: el enlace menciona a BBVA, Banamex, Banorte, Santander, el SAT, el IMSS, la CFE, Mercado Libre, Amazon, Correos de México u otras, pero el dominio no es uno de los suyos. También detecta dominios a una letra de distancia, como paypa1.com o banorrte.com.
  • Letras de otros alfabetos (ataque homógrafo): la «а» cirílica y la «a» latina se ven idénticas, pero son caracteres distintos. bbvа.mx con «а» cirílica es otro dominio, que el navegador escribe como xn--bbv-8cd.mx.
  • Dirección IP en lugar de un nombre, incluso disfrazada como número decimal (http://3232235777 es 192.168.1.1).
  • La @ antes del dominio, que hace que lo primero que se lee no cuente.
  • Acortadores (bit.ly, tinyurl.com, cutt.ly…), que esconden el destino.
  • Alojamiento gratuito (web.app, netlify.app, github.io, wixsite.com…), donde cualquiera crea una página en minutos.
  • Redirecciones: un enlace de un sitio conocido que lleva a otro en un parámetro como url= o redirect=. La herramienta también analiza ese destino.
  • Descargas de aplicaciones (.apk, .exe): las «apps del banco» que llegan por mensaje se usan para robar cuentas.
  • Otras señales menores: http sin cifrar, puertos poco comunes, muchos subdominios, varios guiones, palabras de urgencia («verificar», «bloqueo», «aclaración») y terminaciones baratas que aparecen mucho en fraudes, como .top, .xyz o .click.

Si ya abriste el enlace

  • Si no escribiste nada, cierra la página. Abrir un enlace rara vez basta para infectar un teléfono actualizado.
  • Si escribiste tu usuario, contraseña o datos de tarjeta, llama ya a tu banco desde el número de la tarjeta, cambia la contraseña desde la app oficial y bloquea la tarjeta si te lo indican.
  • Si instalaste una aplicación, desinstálala, revisa los permisos de accesibilidad del teléfono y avisa a tu banco.
  • En México puedes reportar el fraude a la Condusef y a la Policía Cibernética de tu estado.

Revisar un enlace en Python

Las comprobaciones básicas, con la biblioteca estándar: urlsplit separa las partes, el códec idna da la forma xn-- y unicodedata dice a qué alfabeto pertenece cada letra.

"""Revisa un enlace sin abrirlo: dominio real, letras de otros alfabetos, IP, @ y marcas en dominios ajenos."""
import ipaddress
import unicodedata
from urllib.parse import urlsplit

SUFIJOS = {"com.mx", "gob.mx", "org.mx", "edu.mx", "co.uk", "com.ar", "com.co"}
MARCAS = {"bbva": ["bbva.mx", "bbva.com"], "paypal": ["paypal.com"], "sat": ["sat.gob.mx"]}


def dominio_registrable(host):
    partes = host.split(".")
    n = 2 if ".".join(partes[-2:]) in SUFIJOS else 1      # sufijo de dos niveles o de uno
    return ".".join(partes[-(n + 1):])


def alfabetos(texto):
    """Primera palabra del nombre Unicode de cada letra: LATIN, CYRILLIC, GREEK..."""
    return {unicodedata.name(c).split()[0] for c in texto if c.isalpha()}


def revisar(enlace):
    partes = urlsplit(enlace if "://" in enlace else "https://" + enlace)
    host = partes.hostname or ""
    senales = []
    if partes.scheme == "http":
        senales.append("sin cifrar (http)")
    if partes.username:
        senales.append(f"lleva «{partes.username}@»: el sitio real es {host}")
    try:
        ipaddress.ip_address(host)
        senales.append("usa una IP en lugar de un dominio")
        return host, senales
    except ValueError:
        pass
    ascii_ = host.encode("idna").decode("ascii")             # forma xn-- que usa el navegador
    if len(alfabetos(host)) > 1:
        senales.append(f"mezcla alfabetos {sorted(alfabetos(host))}: en realidad es {ascii_}")
    real = dominio_registrable(host)
    for marca, oficiales in MARCAS.items():
        if marca in host.replace("-", ".").split(".") and real not in oficiales:
            senales.append(f"menciona «{marca}» pero el dominio es {real}")
    return real, senales


for enlace in ["https://www.bbva.mx/personas",
               "http://bbva.mx.verificacion-cuenta.top/acceso",
               "https://sat.gob.mx@192.168.10.5/pago",
               "https://www.bbvа.mx/"]:                       # la última «а» es cirílica
    real, senales = revisar(enlace)
    print(enlace, "→", real)
    for s in senales or ["sin señales"]:
        print("   -", s)
$ python3 enlace.pyhttps://www.bbva.mx/personas → bbva.mx
   - sin señales
http://bbva.mx.verificacion-cuenta.top/acceso → verificacion-cuenta.top
   - sin cifrar (http)
   - menciona «bbva» pero el dominio es verificacion-cuenta.top
https://sat.gob.mx@192.168.10.5/pago → 192.168.10.5
   - lleva «sat.gob.mx@»: el sitio real es 192.168.10.5
   - usa una IP en lugar de un dominio
https://www.bbvа.mx/ → bbvа.mx
   - mezcla alfabetos ['CYRILLIC', 'LATIN']: en realidad es www.xn--bbv-8cd.mx

Para extraer el dominio registrable de cualquier terminación, en un programa de verdad usa la lista completa de sufijos públicos, por ejemplo con la biblioteca tldextract. Más herramientas en decodigo.com/herramientas.

Letras parecidas: confusables.txt de Unicode y UTS #39. Conversión de dominios internacionales: RFC 3492 (Punycode). Terminaciones frecuentes en fraudes: informes de Spamhaus e Interisle. Dominios registrables: Public Suffix List.