Crawling
Las primeras páginas web podían recorrerse siguiendo enlaces HTML hasta agotar el sitio. Una aplicación actual puede construir rutas en JavaScript, cargar datos mediante APIs, cambiar el grafo después del login y generar enlaces distintos para cada objeto. El principio del crawling sigue siendo el mismo: partir de una URL, observar referencias y recorrer los destinos nuevos. Lo que ha cambiado es la cantidad de estado que determina qué referencias llegan a existir.
Por eso un crawl no representa «la aplicación». Representa el grafo visible desde unas URL iniciales, una identidad, un navegador o cliente y un instante concretos. Se diferencia del descubrimiento de contenido en que sigue referencias observadas en vez de adivinar nombres desde una wordlist. Ambas técnicas cubren ausencias distintas.
Modelar el recorrido
Sección titulada «Modelar el recorrido»Antes de ejecutar un crawler, define:
- URL iniciales: puntos desde los que comenzará el recorrido
- scope: orígenes, hostnames o expresiones que puede seguir
- profundidad: número máximo de saltos desde cada URL inicial
- estado: sesión anónima, sesión autenticada, rol y cookies
- estrategia: recorrido en profundidad o en anchura
- límites: duración, concurrencia, rate y tamaño de respuesta
- artefactos: URLs, peticiones, respuestas, formularios, scripts y errores
El recorrido en anchura visita primero los destinos cercanos a cada URL inicial y produce pronto una vista amplia. El recorrido en profundidad sigue una rama antes de volver a las pendientes. Ninguno garantiza cobertura completa. La aplicación puede generar URLs de forma dinámica, ocultar rutas tras eventos del navegador o formar ciclos.
Normalización y deduplicación
Sección titulada «Normalización y deduplicación»Las URL que parecen distintas pueden representar el mismo recurso:
/products?id=7/products?id=8/products?sort=name&id=7/products#detailsEl fragmento #details no se envía al servidor en una petición HTTP ordinaria. Los valores de query pueden cambiar la entidad, el orden o el estado y no deben eliminarse sin entender su función. Los calendarios, buscadores y parámetros aleatorios pueden crear espacios prácticamente infinitos.
Un crawler mantiene una clave de deduplicación y reglas de canonicalización. Si ignora todos los valores, puede perder objetos diferentes. Si conserva cada combinación, puede entrar en una trampa de rastreo. Registra qué regla se aplicó para interpretar la cobertura obtenida.
La decisión depende de la semántica observada. En /products?id=7, el valor parece seleccionar una entidad. En ?utm_source=..., puede limitarse a atribución. Compruébalo con dos peticiones antes de eliminar el parámetro de la clave. Una regla de normalización correcta para un sitio puede destruir cobertura en otro.
Rastrear HTML y JavaScript con Katana
Sección titulada «Rastrear HTML y JavaScript con Katana»Katana acepta una URL mediante -u. -d 3 limita el recorrido a tres niveles. -jc extrae endpoints de ficheros JavaScript. -fx incorpora formularios y campos a la salida JSONL. -j selecciona ese formato y -o guarda el archivo:
katana -u BASE_URL \ -d 3 \ -jc \ -fx \ -j \ -o crawl.jsonlLa extracción de JavaScript analiza cadenas y patrones observables. No ejecuta necesariamente la lógica que construye una URL en tiempo de ejecución. Revisa los scripts encontrados, los endpoints XHR y las referencias a otros hostnames.
Para aplicaciones que dependen del DOM y de JavaScript ejecutado, -hl activa el modo headless híbrido. -xhr extrae el método y la URL de peticiones XHR en la salida JSONL:
katana -u BASE_URL \ -hl \ -xhr \ -d 3 \ -j \ -o crawl-headless.jsonlEl navegador ejecuta código cliente, crea almacenamiento local y puede enviar peticiones que un analizador estático nunca produciría. También consume más CPU y memoria. Si la aplicación contiene acciones con efecto, un clic, un formulario o una petición generada por el frontend puede cambiar datos. Empieza con navegación y extracción. Habilita el relleno automático o acciones adicionales solo después de identificar su función.
Si el modo headless encuentra menos rutas que el rastreo estándar, inspecciona errores de consola, certificados, bloqueos de recursos, tiempo de espera del DOM y detección de automatización. Si encuentra muchas más, separa las peticiones iniciadas por la aplicación de telemetría, extensiones o recursos del propio navegador.
Sesiones y vistas diferentes
Sección titulada «Sesiones y vistas diferentes»Una aplicación no tiene una única superficie. La sesión anónima puede mostrar registro y login. Un usuario autenticado añade perfil, API y operaciones ligadas a su rol. Un panel cargado dentro de un iframe puede pertenecer a otro origen.
Conserva los recorridos por separado:
anonymous/crawl.jsonluser/crawl.jsonladmin/crawl.jsonlNo mezcles cookies ni resultados antes de comparar. Una ruta presente en dos sesiones puede responder con contenido, métodos o campos distintos. La diferencia es parte del mapa.
Katana acepta cabeceras mediante -H con el formato Nombre: valor. Una cookie de laboratorio ya obtenida puede pasarse así:
katana -u BASE_URL \ -H 'Cookie: session=SESSION_VALUE' \ -d 3 \ -j \ -o crawl-authenticated.jsonlSESSION_VALUE es un placeholder y no debe publicarse en notas reutilizables. Una sesión expirada puede transformar silenciosamente todo el recorrido en una vista anónima. Comprueba una URL que distinga ambos estados antes y después del rastreo.
Proxies de interceptación y crawlers
Sección titulada «Proxies de interceptación y crawlers»Burp Suite construye un mapa del sitio a partir del tráfico observado y de su crawler. Un navegador controlado permite mantener sesión, ejecutar JavaScript y revisar cada petición. OWASP ZAP separa el Spider tradicional, adecuado para enlaces HTML, del Client Spider orientado a aplicaciones modernas ejecutadas en navegador.
Estas herramientas son especialmente útiles cuando hay autenticación, tokens antifalsificación, flujos con varios pasos o acciones que necesitan revisión manual. Un crawler de línea de comandos facilita resultados reproducibles y pipelines. Ambos enfoques pueden compartir las URL iniciales y después comparar cobertura.
Interpretar el grafo
Sección titulada «Interpretar el grafo»Clasifica cada nodo por método, autenticación, tipo de contenido y procedencia. Presta atención a:
- formularios y parámetros de entrada
- endpoints de API y esquemas publicados
- ficheros JavaScript y source maps
- documentos, copias, logs y listados de directorio observados
- redirecciones a otros orígenes
- comentarios, metadatos y nombres internos
- rutas que solo aparecen en un estado de sesión
Un enlace externo no entra automáticamente en el scope, pero sí aporta una relación. Un 404 enlazado puede señalar contenido retirado o una ruta generada incorrectamente. El resultado del rastreo alimenta el análisis manual y el futuro descubrimiento por fuzzing.
Diagnosticar cobertura incompleta
Sección titulada «Diagnosticar cobertura incompleta»Si una ruta visible en el navegador no aparece en el output, reproduce el camino que la creó. Comprueba si nace del HTML recibido, de un bundle, de una petición XHR, de un evento de usuario o de un estado almacenado. Después compara sesión, cabeceras, tiempo de espera y scope. Añadir profundidad solo ayuda cuando la URL ya forma parte de una cadena que el crawler puede observar.
Cuando la ejecución crece sin estabilizarse, busca calendarios, paginación, identificadores aleatorios, filtros combinatorios y enlaces que incorporan la sesión. Aísla el patrón, define una regla de exclusión y conserva varias muestras. El criterio de parada debe poder explicar qué familia se dejó fuera y por qué no añadía una nueva clase de recurso.