Sérialisation serveur : ce que le framework expose à votre place
Pourquoi le protocole entre composants serveur et client est une surface d'attaque située avant votre code, et les décisions de conception qui limitent ce qu'une faille du framework peut atteindre.
Par Elias Varen7 min de lectureMembres
Aucune route n'a été écrite. Il y a une fonction, avec "use server" en tête de fichier, passée à un formulaire. À la compilation, le framework lui a attribué un identifiant et a ouvert un point d'entrée HTTP qui l'appelle. Ce point d'entrée accepte une requête de n'importe qui, décode son corps dans un format que vous n'avez jamais lu, reconstruit des arguments, et ne donne la main à votre code qu'ensuite.
Tout ce qui se passe avant ce moment est du code que vous ne possédez pas, qui traite une entrée hostile et qui s'exécute avant votre vérification de session. Une classe entière de failles vit à cet endroit, celles de la désérialisation. Quand une vulnérabilité critique touche cette couche, elle touche d'un coup toutes les applications bâties dessus, y compris celles dont le code applicatif est irréprochable.
Un format qui transporte plus que des données
Le JSON ne sait décrire que des données inertes : chaînes, nombres, listes, objets. Le protocole qui relie composants serveur et composants client doit transporter davantage, des dates, des références partagées, des promesses qui se résolvent plus tard, des flux, des formulaires, et surtout des références vers du code (« ce composant client-là », « cette fonction serveur-là »). Ce protocole circule dans les deux sens : le serveur l'émet vers le navigateur, et le navigateur l'émet vers le serveur quand il appelle une fonction serveur avec ses arguments.
Navigateur Serveur
────────── ───────
appel d'une fonction serveur ──▶ 1. lit l'identifiant de la fonction
(arguments sérialisés) 2. décode les arguments ◀── code du framework,
3. reconstruit les objets entrée non fiable
─────────────────────────────
4. votre fonction : session, droits, validationLa règle générale de la désérialisation tient en une phrase : plus un format est expressif, plus son décodeur ressemble à un interprète. Un décodeur qui doit résoudre des références, suivre des chemins dans des objets, instancier des structures riches ou relier des morceaux arrivés dans le désordre exécute une logique pilotée par l'entrée. Si l'entrée peut désigner quelque chose que le concepteur n'avait pas prévu de rendre désignable, l'attaquant cesse de fournir des données et se met à piloter le décodeur. Dans les cas graves, cela va jusqu'à l'exécution de code sur le serveur.
À lire ensuite
Toute la rubrique WebWeb
Server Components : le modèle mental et la facture
Ce que la frontière serveur/client découpe réellement, ce qu'elle coûte en octets, en CPU et en couplage, et le critère pour savoir si votre application y gagne.
7 minLecture libre
Web
Sortir de Next.js : le coût de sortie mesuré
Une méthode pour inventorier ce qui vous attache à Next.js, chiffrer la sortie en jours plutôt qu'en opinions, et garder ce coût bas sans quitter le framework.
6 minMembres
Web
Le cache de Next.js : quatre couches, quatre surprises
Les quatre couches de cache de Next.js, la manière dont chacune sert une donnée périmée ou celle du voisin, et la politique d'invalidation que j'applique sur une plateforme multi-tenant.
6 minMembres