Detección de dominios lookalike: algoritmos y métodos técnicos
Guía técnica para detectar dominios similares: distancia Damerau-Levenshtein, homoglifos y patrones estructurales. Con ejemplos de código Python.
Un dominio lookalike es un nombre de dominio diseñado para parecerse visual o fonéticamente a uno legítimo. La detección sistemática de estos dominios se basa en tres familias de técnicas: algoritmos de distancia de edición, sustitución de homoglifos y análisis de patrones estructurales. Para un dominio como "acme.com", un análisis completo puede generar varios cientos de variantes candidatas antes de filtrar. Este artículo cubre cada método con ejemplos concretos y código, y explica cómo Domain Sentinel los combina en un pipeline de vigilancia continua.
Distancia de edición: Levenshtein y Damerau-Levenshtein
La distancia de Levenshtein entre dos cadenas es el número mínimo de inserciones, eliminaciones y sustituciones de un solo carácter necesarias para transformar una en la otra. La variante Damerau-Levenshtein añade transposiciones de caracteres adyacentes, cubriendo los errores tipográficos más frecuentes en condiciones reales.
Ejemplos concretos para la cadena "acme":
- "acme" vs "acmee": distancia 1 (inserción de un carácter)
- "acme" vs "acne": distancia 1 (sustitución de "m" por "n")
- "acme" vs "amce": distancia Damerau 1 (transposición), distancia Levenshtein 2
Para la vigilancia de marcas, se usa típicamente un umbral de distancia de 1 o 2 dependiendo de la longitud del nombre. Los nombres cortos (4-5 caracteres) necesitan un umbral de 1 para evitar falsos positivos; los más largos pueden tolerar 2.
Implementación en Python
def damerau_levenshtein(s1, s2):
d = {}
len1, len2 = len(s1), len(s2)
for i in range(-1, len1 + 1):
d[(i, -1)] = i + 1
for j in range(-1, len2 + 1):
d[(-1, j)] = j + 1
for i in range(len1):
for j in range(len2):
cost = 0 if s1[i] == s2[j] else 1
d[(i, j)] = min(
d[(i - 1, j)] + 1,
d[(i, j - 1)] + 1,
d[(i - 1, j - 1)] + cost
)
if i > 0 and j > 0 and s1[i] == s2[j-1] and s1[i-1] == s2[j]:
d[(i, j)] = min(d[(i, j)], d[(i-2, j-2)] + cost)
return d[(len1 - 1, len2 - 1)]
def generate_variantes_distancia_1(nombre):
alfabeto = 'abcdefghijklmnopqrstuvwxyz0123456789-'
variantes = set()
for i in range(len(nombre)):
variantes.add(nombre[:i] + nombre[i+1:])
for c in alfabeto:
variantes.add(nombre[:i] + c + nombre[i+1:])
variantes.add(nombre[:i] + c + nombre[i:])
if i < len(nombre) - 1:
variantes.add(nombre[:i] + nombre[i+1] + nombre[i] + nombre[i+2:])
return variantes - {nombre}
Generación de variantes a distancia 1
Las cuatro categorías de modificaciones y el volumen que producen para un nombre de longitud n:
- Eliminaciones: n variantes
- Sustituciones: n × 36 variantes (26 letras + 10 dígitos + guion)
- Inserciones: (n+1) × 36 variantes
- Transposiciones: (n-1) variantes
Para un nombre de 5 letras, esto produce unas 380-420 variantes brutas antes de filtrar las cadenas inválidas en DNS y eliminar duplicados.
Homoglifos: el ataque de sustitución de caracteres Unicode
Un homoglifo es un carácter Unicode que parece visualmente idéntico a otro. Los ataques por homoglifos explotan los nombres de dominio internacionalizados (IDN), que permiten caracteres no ASCII codificados en Punycode. La "а" cirílica (U+0430) es visualmente indistinguible de la "a" latina (U+0061) en prácticamente todas las fuentes. Un atacante puede registrar "аpple.com" con una "а" cirílica y ese dominio aparece como "apple.com" en muchos contextos.
Pares de homoglifos más frecuentemente explotados:
| Original | Sustitutos habituales |
|---|---|
| a | а (U+0430 cirílico), ɑ (U+0251), α (U+03B1 griego) |
| o | о (U+043E cirílico), 0 (cero), ο (U+03BF griego) |
| e | е (U+0435 cirílico), ё (U+0451) |
| c | с (U+0441 cirílico) |
| p | р (U+0440 cirílico) |
| l | 1 (uno), I (i mayúscula), |
| n | п (U+043F cirílico) |
| i | í (U+00ED), ï (U+00EF), 1 (uno) |
Detección programática de homoglifos
El Consorcio Unicode mantiene un conjunto de datos público "confusables" que mapea caracteres con sus equivalentes visuales. Un enfoque práctico en Python:
HOMOGLIFOS = {
'a': ['а', 'ɑ', 'α'],
'o': ['о', '0', 'ο'],
'e': ['е', 'ё'],
'c': ['с'],
'l': ['1', 'I'],
'p': ['р'],
}
def generate_variantes_homoglifos(dominio):
nombre, tld = dominio.rsplit('.', 1)
variantes = set()
def recursion(indice, actual):
if indice == len(nombre):
if actual != nombre:
variantes.add(f"{actual}.{tld}")
return
char = nombre[indice]
recursion(indice + 1, actual + char)
for sustituto in HOMOGLIFOS.get(char, []):
recursion(indice + 1, actual + sustituto)
recursion(0, '')
return variantes
Atención a la explosión combinatoria: un nombre de 6 letras donde cada letra tiene 3 homoglifos posibles genera hasta 3^6 = 729 variantes solo por homoglifos. En la práctica, se aplica una profundidad máxima de sustitución (típicamente 2 sustituciones por dominio) para mantener el conjunto manejable.
Cómo gestionan los navegadores modernos los IDN
Chrome y Firefox muestran la representación Punycode (empezando por xn--) en lugar del nombre de dominio Unicode cuando un dominio mezcla scripts diferentes (por ejemplo, latino y cirílico en la misma etiqueta). Así, "аpple.com" con "а" cirílica aparece en la barra de direcciones del navegador como xn--pple-43d.com. Sin embargo, los dominios puramente cirílicos (donde toda la etiqueta es cirílica) pueden seguir mostrándose en Unicode, por lo que la detección de homoglifos sigue siendo relevante. El Punycode para аcme.com (а cirílica) es xn--cme-9cd.com.
Análisis estructural: variantes de TLD y patrones de prefijo/sufijo
La tercera familia no manipula caracteres individuales sino la estructura del propio dominio.
Intercambio de TLD
Reemplazar el TLD es la variante más sencilla de generar y a menudo la más relevante comercialmente. Para "acme.com" produce acme.net, acme.io, acme.co, acme.app, acme.shop. Los TLDs más frecuentemente utilizados para abusos:
- .co (muy habitual: visualmente cercano a .com y un ccTLD legítimo)
- .net (establecido, ampliamente reconocido)
- .io (estándar en el sector tecnológico, confusión creciente con .com)
- .app (móvil y SaaS)
- .shop, .store (comercio electrónico)
- .xyz, .top, .tk, .ml, .ga (a menudo gratuitos; usados desproporcionadamente en phishing)
Patrones de prefijo y sufijo habituales
Estos patrones son con frecuencia más peligrosos que los simples errores tipográficos porque pueden engañar a usuarios experimentados:
get{marca}.com try{marca}.com mi{marca}.com
{marca}app.com {marca}hq.com {marca}online.com
{marca}-login.com {marca}-seguro.com {marca}-cuenta.com
{marca}oficial.com {marca}soporte.com {marca}-ayuda.com
{marca}pro.com {marca}plus.com {marca}portal.com
{marca}-verificacion.com
Palabras como "login", "seguro", "cuenta" y "verificacion" en un nombre de dominio son señales de alarma, no de confianza. Los servicios legítimos raramente necesitan incluirlas en su nombre de dominio principal.
Separadores y variantes compuestas
Si el nombre de tu marca es compuesto ("Domain Sentinel"), vigilar: domainsentinel.com, domain-sentinel.com, sentineldomain.com, sentinel-domain.com. Si el nombre de tu marca incluye un guion, vigilar también la versión sin guion y viceversa.
Combinar métodos: el pipeline completo de detección
Domain Sentinel combina las tres familias en un pipeline secuencial:
- Generar candidatos con variantes Damerau-Levenshtein (distancia 1-2), sustituciones de homoglifos (hasta 2 sustituciones), intercambios de TLD sobre una lista curada y variantes de patrones estructurales (prefijos/sufijos).
- Deduplicar y filtrar para eliminar cadenas inválidas en DNS y reducir el conjunto de candidatos.
- Verificación RDAP en lote para cada candidato: registrado, disponible o pendiente/reservado.
- Clasificar resultados: los nuevos registros disparan alertas; los dominios disponibles pueden marcarse para un posible registro preventivo.
- Priorizar alertas por riesgo: los dominios que combinan múltiples señales de similitud (error tipográfico + palabra clave sospechosa + registrado recientemente) se clasifican más alto que los simples intercambios de TLD con un historial de registro prolongado.
El problema del "ruido" es real: la generación exhaustiva puede producir miles de candidatos. La priorización por distancia de edición, nivel de riesgo del TLD y presencia de palabras clave de alto riesgo (login, seguro, oficial, verificacion, soporte) mantiene la cola de alertas accionable.
Herramientas de código abierto y APIs disponibles
Para equipos que quieren construir su propio pipeline o validar resultados:
dnstwist(Python, código abierto) es la herramienta de referencia para generar variantes de dominios lookalike. Implementa la mayoría de los métodos descritos aquí e incluye lookups RDAP/WHOIS.urlcrazyes similar, centrado en la generación de variantes de typosquatting.- El servicio RDAP de la ICANN en
rdap.orggestiona lookups RDAP individuales de forma gratuita y sin autenticación. - Domain Sentinel automatiza todo el pipeline de forma continua, envía alertas cuando se detectan nuevos registros y gestiona la complejidad de las consultas RDAP y los límites de tasa.
La limitación principal de las herramientas de código abierto: generan variantes pero no monitorizan continuamente. Ejecutar dnstwist una vez muestra lo que está registrado hoy. Hay que volver a ejecutarlo mañana, pasado mañana, y construir encima un sistema propio de notificaciones. Esa es la brecha que Domain Sentinel llena.
En la práctica, comenzar con intercambios de TLD y patrones estructurales da la señal más rápida con menos ruido. Añade variantes Damerau-Levenshtein para cobertura exhaustiva de errores tipográficos, luego incorpora la detección de homoglifos para cobertura completa. El análisis completo de un nombre de marca de 6 caracteres sobre 20 TLDs y 30 patrones de prefijo/sufijo produce aproximadamente 2.000-3.000 dominios candidatos que vale la pena verificar vía RDAP. Ejecuta tu marca en Domain Sentinel para ver cuáles de ellos ya están registrados.
Empieza con un dominio que te importe
Búscalo gratis. Para recibir alertas cuando el estado cambie o la expiración se acerque, crea una cuenta. Son 30 segundos.