Tu sitio ya le cuenta a todo el mundo de qué está hecho.
Introduce una URL y nombramos el constructor, el framework, la base de datos, el proveedor de autenticación, el alojamiento y el servidor que publica sobre sí mismo, y después ejecutamos las cuatro comprobaciones que solo tienen sentido cuando eso se conoce. Nada de esto sale de un sondeo: está todo en la respuesta que tus visitantes ya reciben.
Qué comprueba esto, y cómo es una buena respuesta
Qué se puede ver, y por qué es visible
Nada de esto está oculto. Un framework se anuncia porque no le queda otra: Next.js carga sus bundles desde /_next/static/, Vite emite una ruta de assets predecible, a Supabase se le llama en una URL de proyecto que tiene que estar en tu JavaScript para que el navegador pueda alcanzarla, y muchísimos servidores siguen mandando una cabecera Server con un número de versión dentro. Leemos la misma página y los mismos scripts que lee un navegador, y comparamos lo que vuelve con una tabla de marcadores. Aquí no se adivinan rutas, y no hay ninguna petición que tus propios visitantes no hagan ya.
Un servidor de desarrollo que acabó desplegado
El hallazgo más fuerte de esta página, y sorprendentemente común. El servidor de desarrollo de Vite no es un servidor web: lee del directorio del proyecto en cada petición, compila sobre la marcha y expone una ruta /@fs/ que puede salir del propio directorio del proyecto. Existe para que guardar un archivo actualice tu navegador, y nunca se escribió para dar la cara a internet. Llega a producción siempre igual: alguien ejecuta npm run dev, apunta un túnel o un alojamiento hacia él para enseñárselo a un compañero, y eso se convierte en el despliegue. Si la página carga /@vite/client, eso es lo que pasó.
Una build de desarrollo donde debería ir la de producción
React, Vue y Angular publican dos builds cada uno. La de desarrollo conserva los avisos, los nombres de componentes y la comprobación de tipos de propiedades; la de producción lo quita todo. Servir la de desarrollo no es un agujero por el que entra un atacante, pero es varias veces más JavaScript del que la página necesita, medible en lentitud, y describe tu árbol de componentes a cualquiera que abra el devtools. Solo hacemos esta pregunta cuando hemos reconocido un framework que tiene dos builds entre las que elegir, porque en una página estática no existe tal cosa como un bundle de desarrollo y decirte que has aprobado sería no decirte nada.
Datos del servidor incrustados en la página
Next.js escribe todo lo que devuelven tus props de servidor dentro del HTML de cada página que renderiza, en un bloque __NEXT_DATA__. Así funciona el framework y no es un defecto. El defecto es el error fácil que vive al lado: consultas un registro de usuario para mostrar un nombre, devuelves el registro entero, y ahora el correo, el identificador interno y el rol están en el código fuente de la página para quien pulse view-source. Buscamos nombres de campo que suenan a registros en lugar de a datos de presentación, y reportamos solo los nombres, nunca los valores. Este puede dar falso positivo, así que pedimos dos antes de decir nada, y lo redactamos como algo que mirar, no como algo que arreglar.
Software fuera de su ventana de soporte
Cuando una versión es legible, la contrastamos con una tabla pequeña de fechas de fin de vida: PHP, Apache, IIS, OpenSSL, jQuery, Bootstrap, AngularJS y Vue 2. Estar fuera de soporte no significa que hayan entrado en el sitio. Significa que el motivo por el que tienes derecho a sentirte seguro, que las correcciones siguen llegando, dejó de aplicar en una fecha concreta, y todo lo encontrado desde entonces sigue ahí. Lo contrastamos con las fechas que publica el propio proveedor, así que puedes comprobar nuestra cuenta. Lo que deliberadamente no hacemos es nombrar un CVE. Eso requeriría una base de vulnerabilidades y un emparejamiento de rangos de versión que aquí no tenemos, y un escáner que adivina fallos concretos es peor que uno que te dice que la versión es vieja y se detiene.
Por qué nada de esto puntúa
Reconocer WordPress no es un hallazgo. Reconocer PHP, Vercel o Stripe tampoco. Muchas herramientas presentan una lista de tecnologías como si cada entrada fuera un cargo, y es la forma más rápida de volver poco fiable un informe: señala cosas que no se pueden arreglar y que no valdría la pena arreglar. El panel de stack de esta página no te cuesta nada. Solo las cuatro comprobaciones de arriba pueden producir un hallazgo, y solo cuando de verdad han encontrado algo.
Cómo corregirlo
Tres arreglos, en el orden en que suelen hacer falta: deja de publicar el servidor de desarrollo, deja de publicar los archivos de mapa y la cabecera del framework, y deja de anunciar versiones que todavía no has actualizado. El último es cosmético por sí solo y merece la pena igualmente, porque es la diferencia entre ser un objetivo concreto y pasar desapercibido en un barrido.
# The dev server is not a web server. It reads from your project
# directory on every request and serves whatever it finds, which is
# why /@fs/ can walk outside the project root at all.
# Wrong, and the single most common way this happens:
npm run dev # then a tunnel or a host pointed at :5173
# Right:
npm run build # emits dist/
npm run preview # serves dist/ locally, to check it first
# Then deploy dist/ as static files. On a host that runs a command
# for you, the build command is 'npm run build' and the publish
# directory is 'dist' (Vite) or 'build' (Create React App).// vite.config.js -- source maps off, which is the default but
// worth stating, because a debugging session that flipped it on
// is how most of them end up in production.
export default {
build: { sourcemap: false },
};
// next.config.js
module.exports = {
productionBrowserSourceMaps: false,
// Also drops the "X-Powered-By: Next.js" banner, which is the
// header that tells a scanner exactly which framework to target.
poweredByHeader: false,
};# nginx: stop announcing the version. server_tokens off leaves
# "nginx" but removes the number, which is the part that tells
# someone which published bugs to try.
server_tokens off;
# Anything proxied from PHP, Express or Rails announces itself too:
proxy_hide_header X-Powered-By;
proxy_hide_header X-AspNet-Version;
# Caddy, equivalent:
# header {
# -Server
# -X-Powered-By
# }
# Express, at the top of the app:
# app.disable("x-powered-by");
# This is cosmetic on its own. It does not patch anything, it just
# stops handing over the version. Upgrade as well.Solo podemos nombrar lo que el sitio publica. Un stack que no anuncia nada es invisible para nosotros, y un resultado vacío aquí significa que no reconocimos nada, no que no haya nada que reconocer. Lo contrario importa más: una tecnología que nombramos es una tecnología que avistamos, no una que probamos. Leer Server: Apache/2.4.41 nos dice cuál es la cadena de versión, no si está parcheada, y reconocer Supabase no dice absolutamente nada sobre si tu row-level security está activo, que es la pregunta que de verdad decide si tus datos son legibles. Esa necesita el código. Si quieres las comprobaciones que dependen del stack y no solo el stack, el escaneo de superficie completo las ejecuta todas juntas y puntúa el resultado.