Analyseur de pile technique

Votre site raconte déjà à tout le monde de quoi il est fait.

Saisissez une URL et nous nommons l'outil de création, le framework, la base de données, le fournisseur d'authentification, l'hébergement et le serveur qu'il publie sur lui-même, puis nous lançons les quatre vérifications qui n'ont de sens qu'une fois cela connu. Rien ici ne vient d'un sondage : tout est dans la réponse que vos visiteurs reçoivent déjà.

Examinez des sites qui vous appartiennent ou que vous êtes autorisé à tester. Nous demandons la page comme le ferait un navigateur et lisons ce qui revient. Consultez nos conditions.

Ce que cela vérifie, et à quoi ressemble une bonne réponse

Ce que nous pouvons voir, et pourquoi c'est visible

Rien de tout cela n'est caché. Un framework s'annonce parce qu'il le doit : Next.js charge ses bundles depuis /_next/static/, Vite produit un chemin d'assets prévisible, Supabase est appelé sur une URL de projet qui doit figurer dans votre JavaScript pour que le navigateur l'atteigne, et quantité de serveurs envoient encore un en-tête Server avec un numéro de version dedans. Nous lisons la même page et les mêmes scripts qu'un navigateur, et nous comparons ce qui revient à une table de marqueurs. Ici, aucun chemin n'est deviné, et aucune requête n'est faite que vos propres visiteurs ne fassent déjà.

Un serveur de développement parti en production

Le constat le plus fort de cette page, et étonnamment fréquent. Le serveur de développement de Vite n'est pas un serveur web : il lit dans le répertoire du projet à chaque requête, compile à la volée et expose une route /@fs/ capable de sortir de la racine du projet. Il existe pour qu'enregistrer un fichier rafraîchisse votre navigateur, et il n'a jamais été écrit pour affronter internet. Il arrive en production toujours de la même façon : quelqu'un lance npm run dev, pointe un tunnel ou un hébergeur dessus pour le montrer à un collègue, et cela devient le déploiement. Si la page charge /@vite/client, c'est ce qui s'est passé.

Une build de développement là où il faudrait celle de production

React, Vue et Angular livrent chacun deux builds. Celle de développement conserve les avertissements, les noms de composants et la vérification des types de propriétés ; celle de production retire tout. Servir celle de développement n'est pas une brèche par laquelle un attaquant passe, mais c'est plusieurs fois plus de JavaScript que la page n'en a besoin, mesurablement plus lent à exécuter, et cela décrit votre arbre de composants à quiconque ouvre les devtools. Nous ne posons cette question qu'après avoir reconnu un framework qui propose deux builds, car sur une page statique il n'existe pas de bundle de développement et vous dire que vous avez réussi ne vous dirait rien.

Des données serveur intégrées à la page

Next.js écrit tout ce que vos props serveur renvoient dans le HTML de chaque page qu'il rend, à l'intérieur d'un bloc __NEXT_DATA__. C'est ainsi que le framework fonctionne et ce n'est pas un défaut. Le défaut, c'est l'erreur facile juste à côté : vous récupérez une fiche utilisateur pour afficher un nom, vous renvoyez la fiche entière, et voilà l'adresse e-mail, l'identifiant interne et le rôle dans le source de la page pour quiconque fait view-source. Nous cherchons des noms de champs qui évoquent des enregistrements plutôt que des données d'affichage, et nous rapportons uniquement les noms, jamais les valeurs. Celui-ci peut donner un faux positif, alors nous en exigeons deux avant de dire quoi que ce soit, et nous le formulons comme quelque chose à regarder, pas comme quelque chose à corriger.

Un logiciel au-delà de sa fenêtre de support

Quand une version est lisible, nous la confrontons à une petite table de dates de fin de vie : PHP, Apache, IIS, OpenSSL, jQuery, Bootstrap, AngularJS et Vue 2. Être hors support ne veut pas dire que le site a été compromis. Cela veut dire que la raison pour laquelle vous êtes en droit de vous sentir en sécurité, à savoir que les correctifs continuent d'arriver, a cessé de s'appliquer à une date précise, et que tout ce qui a été trouvé depuis est toujours là. Nous confrontons cela aux dates publiées par l'éditeur lui-même, vous pouvez donc vérifier notre calcul. Ce que nous refusons délibérément, c'est de nommer un CVE. Cela demanderait une base de vulnérabilités et une correspondance de plages de versions dont nous ne disposons pas ici, et un scanner qui devine des failles précises vaut moins qu'un scanner qui dit que la version est ancienne et s'arrête là.

Pourquoi rien de tout cela n'entre dans le score

Reconnaître WordPress n'est pas un constat. Reconnaître PHP, Vercel ou Stripe non plus. Beaucoup d'outils présentent une liste de technologies comme si chaque entrée était un chef d'accusation, et c'est le moyen le plus rapide de rendre un rapport peu digne de confiance : il signale des choses qu'on ne peut pas corriger et qu'il ne vaudrait pas la peine de corriger. Le panneau de pile de cette page ne vous coûte rien. Seules les quatre vérifications ci-dessus peuvent produire un constat, et uniquement quand elles ont réellement trouvé quelque chose.

Comment corriger

Trois correctifs, dans l'ordre où ils sont généralement nécessaires : cessez de livrer le serveur de développement, cessez de livrer les fichiers de map et la bannière du framework, et cessez d'annoncer des versions que vous n'avez pas encore mises à jour. Le dernier est cosmétique en soi et mérite d'être fait quand même, car c'est la différence entre être visé précisément et passer entre les mailles d'un balayage.

Livrez la build, pas le serveur de développement
# 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).
Coupez les source maps et la bannière du framework
// 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,
};
Cessez d'annoncer les versions
# 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.
Ce que cet outil ne peut pas voir

Nous ne pouvons nommer que ce que le site publie. Une pile qui n'annonce rien nous est invisible, et un résultat vide ici signifie que nous n'avons rien reconnu, pas qu'il n'y a rien à reconnaître. L'inverse compte davantage : une technologie que nous nommons est une technologie que nous avons repérée, pas une technologie que nous avons testée. Lire Server: Apache/2.4.41 nous donne la chaîne de version, pas si elle est corrigée, et reconnaître Supabase ne dit absolument rien sur l'activation de votre row-level security, qui est pourtant la question qui décide vraiment si vos données sont lisibles. Celle-là demande le code. Si vous voulez les vérifications qui dépendent de la pile et pas seulement la pile, le scan de surface complet les exécute toutes ensemble et note le résultat.

Scanner aussi le codeGratuit pour démarrer. Connectez un dépôt et le premier scan tourne en deux minutes environ.