Skip to content

Encodage XSS : l'ordre des transformations compte

URL encoding, entités HTML et Base64 ne sont pas interchangeables. En test XSS, l'ordre d'application change complètement le résultat.

Publié le 3 min de lecture

L'encodage est souvent traité comme une finition. On fabrique une chaîne, puis on la "passe en URL encoded" ou en entités HTML quand l'application refuse certains caractères. En pratique, l'encodage fait partie du test. L'ordre change la donnée, et donc le comportement observé.

Un navigateur ne lit pas une intention. Il lit des octets, des caractères, puis des tokens selon un contexte. Entre la saisie et le DOM final, plusieurs composants peuvent décoder une fois, deux fois, ou pas du tout. C'est là que les conclusions rapides deviennent dangereuses.

Double encodage, double confusion

Prenons une valeur encodée deux fois en URL. Une application peut décoder une première fois au niveau du framework HTTP, puis une deuxième fois dans une logique métier écrite à la main. Une autre ne fera qu'un seul décodage. Une troisième décodera côté serveur, réencodera dans le template, puis le navigateur interprétera le résultat final.

Le même input peut donc produire trois observations différentes.

entrée        : valeur encodée deux fois
serveur       : decodeURIComponent une fois
template      : échappement HTML
navigateur    : parse du DOM final

Ce chemin n'a rien d'exotique. Il apparaît dans les formulaires legacy, les redirects, les paramètres de recherche, les fragments d'URL recopiés dans l'interface et les intégrations de tracking.

Pourquoi un pipeline explicite aide

Dans xsspayloads, l'intérêt d'une chaîne d'encodage n'est pas seulement de produire une variante. C'est de garder la mémoire du chemin. URL puis HTML entities n'est pas équivalent à HTML entities puis URL. Base64 autour d'une chaîne déjà encodée ne raconte pas la même chose que Base64 avant encodage URL.

Cette traçabilité compte dans un rapport. Un correcteur doit pouvoir reproduire le comportement sans deviner quelle transformation a été appliquée en premier.

Un exemple de note utile :

Transformations testées : URL encode -> HTML entities
Observation : le serveur décode l'URL, le template conserve les entités, le DOM final reste inerte
Conclusion : pas d'exécution dans ce contexte, mais normalisation côté serveur à documenter

Ce n'est pas spectaculaire. C'est propre.

Les filtres cassent souvent au mauvais endroit

Les filtres maison bloquent parfois la chaîne avant transformation, alors que le danger arrive après décodage. D'autres filtrent après un premier décodage mais avant une seconde normalisation. Ce genre de code donne des résultats instables et des exceptions bizarres en production.

Le bon correctif n'est généralement pas "ajouter un filtre de plus". Il faut encoder à la sortie selon le contexte exact : HTML text, attribut, JavaScript string, URL, CSS. L'encodage d'entrée peut aider à normaliser, mais il ne remplace pas l'encodage de sortie.

Tester moins, observer mieux

Multiplier les variantes sans noter les transformations crée du bruit. Mieux vaut tester moins de chaînes, mais enregistrer précisément l'ordre, le contexte cible et le DOM obtenu.

Un générateur sérieux doit donc afficher la recette, pas seulement le résultat. Sinon, l'auditeur obtient une chaîne qui "a marché" une fois, sans comprendre pourquoi. Et ça, en sécurité applicative, c'est rarement une victoire.

Articles liés

Les templates accélèrent les tests répétitifs, mais ils peuvent aussi figer de mauvaises hypothèses et produire des résultats trompeurs.
Un playground XSS est utile pour observer le comportement du navigateur, mais il ne reproduit jamais toute la complexité d'une application réelle.
Un test XSS sérieux commence par le contexte d'injection. HTML, attribut, JavaScript, URL ou CSS ne se testent pas avec la même logique.