Le header qui saute la vérification : contourner le middleware Next.js
Le défi
La console interne de Mereton place son mur de connexion dans le middleware Next.js : chaque requête vers /admin est censée passer d'abord par lui. Un chercheur a remarqué que le framework fait confiance à un header qu'il utilise pour communiquer avec lui-même, et que rien ne vous empêche d'envoyer ce header depuis l'extérieur. La requête vers le dashboard d'administration est chargée dans l'éditeur. Faites en sorte que le middleware s'efface, puis lisez la clé d'API admin que le dashboard affiche une fois que vous êtes dedans.
Ce que tu vas apprendre
- Expliquer pourquoi une valeur qu'un framework utilise pour se faire confiance à lui-même ne doit jamais être acceptée d'un client
- Reproduire le contournement x-middleware-subrequest en envoyant le header avec une valeur répétée
- Lire une réponse de redirection pour y repérer l'indice qui nomme le middleware contourné
- Faire le lien avec la règle X-Forwarded-For : faire confiance à ce que votre edge écrit, pas à ce qui arrive
- Reconnaître qu'une authentification appliquée uniquement dans un middleware est un point unique que l'on peut contourner
Compétences testées
Prérequis
- La structure d'une requête HTTP
- Le rôle d'un middleware dans un framework web
Comment ça marche
Un framework web envoie souvent des requêtes vers ses propres composants internes, et les marque avec un header pour ne pas boucler indéfiniment. Next.js utilisait x-middleware-subrequest exactement pour ça. Le problème, c'est que ce même header décidait si le middleware s'exécutait : le framework comptait combien de fois le nom du middleware courant y apparaissait, et dès que ce compte atteignait sa limite de récursion de cinq, il supposait une boucle et sautait le middleware.
Rien ne supprimait ce header à l'edge, donc un navigateur pouvait l'envoyer lui aussi. Il suffisait de le définir sur le chemin du module du middleware, répété cinq fois, et la couche d'authentification ne s'exécutait tout simplement pas. La requête atteignait la page protégée comme si elle avait été approuvée.
La règle générale : un jeton qui signifie cette requête est interne doit être infalsifiable depuis l'extérieur, ce qui veut dire en pratique que la frontière doit supprimer toute copie entrante et écrire la sienne. Un header, à lui seul, n'est jamais cela.
Erreurs fréquentes
- Envoyer un seul
middleware. Les anciennes versions de Next.js sautaient le middleware dès une copie, mais celle-ci les compte et ne s'efface qu'à sa limite de récursion de cinq. - Modifier le chemin ou le Host. L'endpoint et l'hôte sont corrects. Seul le header de confiance est la porte d'entrée.
- Voir la redirection vers le login comme une impasse. Son commentaire nomme le module du middleware, qui est la valeur dont vous avez besoin.
- Répondre avec la cible de la redirection.
/login?next=/adminest le mur, pas la récompense.
Comment s'en protéger
Traitez le header comme une entrée hostile.
- Supprimez
x-middleware-subrequestau niveau du CDN ou du reverse proxy pour qu'il ne puisse jamais arriver d'un client. Les versions corrigées du framework le font en interne : mettez à jour. - Ne faites pas dépendre l'authentification d'un seul passage dans un middleware. Revérifiez l'autorisation dans le route handler ou la couche de données, là où un middleware sauté ne change rien.
- Appliquez la même discipline à chaque header de confiance (
X-Forwarded-For,X-Real-IP, headers d'authentification internes) : la seule valeur à laquelle vous pouvez faire confiance est celle que votre proxy le plus externe a écrite.
Solution complète
Statistiques de la communauté
Hacks du jour associés
Contributeurs crédités
Ces hackers ont signalé des problèmes, amélioré le contenu et renforcé cette page.