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.
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.