Langue : en | de | fr | es
Retour aux blogs
prochain article ▶
%20 dans les URL : ce que cela signifie et pourquoi cela apparaît dans les adresses Web

Double encodage dans les URL

Le double encodage dans les URL se produit lorsque des caractères déjà encodés sont encodés une fois de plus. Au lieu de %20 pour un espace, on peut se retrouver avec %2520, parce que le signe pourcentage lui-même a été encodé en %25. Ce problème semble petit dans les journaux, mais il casse les redirections, les paramètres API, les chemins de fichiers, les signatures et les filtres de sécurité.

Le sujet est important car l’encodage des URL est généralement géré simultanément sur plusieurs couches : navigateur, bibliothèque cliente, proxy, framework, routeur et code applicatif. Si deux couches décident toutes les deux d’« aider », l’URL finale change de sens. En production, cela apparaît souvent comme une URL de callback cassée, un flux OAuth échoué, un fichier manquant ou une route qui fonctionne en staging mais pas derrière une passerelle.

Pourquoi les URL doublement encodées apparaissent dans les systèmes réels

Une URL doit être encodée au bon moment et uniquement pour la partie pertinente. Les problèmes commencent lorsque les développeurs encodent la chaîne complète manuellement puis la passent dans un outil qui l’encode à nouveau.

Les causes courantes incluent :

  • encoder un paramètre de requête avant de le donner à URLSearchParams
  • encoder une URL de redirection complète puis l’intégrer dans une autre URL
  • le middleware du framework réécrire des valeurs déjà traitées
  • le code frontend envoyer des entrées encodées à un backend qui les encode à nouveau
  • les règles de proxy ou WAF transformant les composants de requête de manière inattendue

Un exemple visuel simple

Supposons que la valeur originale soit :

/docs/My File.pdf

Encodage unique correct pour un fragment de chemin :

/docs/My%20File.pdf

Après un deuxième passage, cela devient :

/docs/My%2520File.pdf

Le serveur peut maintenant chercher un fichier contenant littéralement %20 dans son nom plutôt qu’un espace.

Comment se présente le problème de double encodage d’URL

La partie la plus difficile est que l’URL semble toujours « encodée », donc les équipes déboguent d’abord la mauvaise couche. Les symptômes dépendent du contexte.

Symptômes typiques en production

Symptôme

Ce que l’on voit

Cause probable

Redirection cassée

L’utilisateur arrive sur une page d’erreur ou une mauvaise route

La cible de redirection est encodée deux fois

Requête API invalide

Le backend reçoit une valeur de filtre corrompue

Le client et le serveur encodent tous les deux

Non-correspondance de signature

La vérification HMAC ou URL signée échoue

L’encodage a changé après la signature

Fichier ou actif manquant

Le chemin se résout incorrectement

Le segment de chemin encodé a été ré-encodé

Contournement de règle de sécurité ou faux positif

Le filtre se comporte de manière incohérente

Différentes étapes de décodage entre les couches

Pourquoi les URL imbriquées sont risquées

Un piège classique apparaît avec les URL de retour :

https://app.example.com/login?next=https://site.example.com/account?tab=settings

Si l’URL interne doit devenir une valeur de paramètre, elle doit être encodée correctement une seule fois. Mais beaucoup d’applications l’encodent d’abord manuellement, puis un routeur ou un client HTTP l’encode à nouveau. Cela crée des flux de callback malformés et des journaux difficiles à lire.

Erreurs de double encodage URL que font les développeurs

L’erreur la plus courante est de ne pas comprendre quelle API attend des données brutes et laquelle attend des données encodées. Les bonnes bibliothèques veulent généralement des valeurs non encodées et gèrent l’échappement en interne.

Exemple en JavaScript

Incorrect :

const next = encodeURIComponent("https://site.example.com/account?tab=settings");

const url = "/login?next=" + encodeURIComponent(next);

Cela produit une valeur transformée deux fois.

Mieux :

const next = "https://site.example.com/account?tab=settings";

const url = "/login?next=" + encodeURIComponent(next);

Exemple avec des constructeurs de requêtes

Mauvais modèle :

  • encoder manuellement name=John Doe
  • passer le résultat dans un constructeur de requête
  • le constructeur de requête encode % à nouveau

Bon modèle :

  • passer John Doe brut
  • laisser une seule couche de confiance construire la chaîne de requête finale

Comment décoder les URL doublement encodées en toute sécurité

Le décodage est simple seulement lorsqu’on sait combien de fois la valeur a été transformée. Le décodage répété aveugle est dangereux, surtout dans le code sensible à la sécurité, car il peut modifier des littéraux intentionnels ou aider des charges utiles à contourner la validation.

Approche pratique de décodage

  1. Inspecter la valeur de requête brute depuis les journaux ou un proxy de débogage.
  2. Décoder une fois et comparer le résultat.
  3. Si des séquences de pourcentage subsistent là où des caractères simples devraient être, vérifier si un second décodage est justifié.
  4. Normaliser uniquement à une limite contrôlée.
  5. Valider après normalisation, pas avant.

Exemple :

Original : hello%2520world

Décoder une fois : hello%20world

Décoder deux fois : hello world

Cela montre une valeur encodée deux fois. Mais ne pas en faire une règle aveugle de « décoder deux fois » pour chaque requête.

Liste de contrôle de débogage plus sûre

  • capturer l’URL brute exacte
  • séparer le chemin, la requête et le fragment
  • tester une étape de décodage à la fois
  • vérifier quelle couche a effectué chaque transformation
  • confirmer si la valeur était censée rester encodée

Prévenir le double encodage URL par conception

Le meilleur correctif est la discipline architecturale, pas le patching.

Règles qui fonctionnent en pratique

  • encoder à la limite où l’URL finale est assemblée
  • conserver les valeurs internes brutes aussi longtemps que possible
  • ne jamais encoder manuellement avant de passer des données à un constructeur d’URL de confiance
  • ne pas décoder et ré-encoder sans raison spécifique
  • documenter si les helpers attendent des entrées brutes ou encodées
  • signer les URL uniquement après que la forme canonique finale est prête

Bonne convention d’équipe

Choisir un seul endroit responsable de la transformation des URL :

  • routeur frontend
  • helper d’URL du backend
  • bibliothèque cliente API
  • couche de normalisation de la passerelle

Une fois la responsabilité claire, le double échappement diminue fortement.

Cas limites de double encodage dans les paramètres imbriqués

Certains cas ressemblent à des bugs mais sont en réalité intentionnels. Par exemple, si une URL est intégrée dans une autre comme donnée, l’encodage doit préserver les séparateurs comme ?, = et & dans la valeur imbriquée. L’essentiel est que l’URL imbriquée ne soit encodée qu’une seule fois pour son rôle de valeur de paramètre, pas répétitivement à chaque saut.

Exemple : paramètre de redirection

/auth?return_to=https%3A%2F%2Fapp.example.com%2Fdashboard%3Fpage%3D2

C’est normal. Cela devient un problème uniquement si la même valeur se transforme ensuite en :

/auth?return_to=https%253A%252F%252Fapp.example.com%252Fdashboard%253Fpage%253D2

Cette deuxième version indique généralement un traitement supplémentaire.

Gérer les valeurs déjà transformées dans les API et le middleware

Les piles de frameworks mélangent souvent la gestion automatique et manuelle. Un proxy inverse peut normaliser une fois, le framework peut décoder dans les paramètres de route, et un middleware personnalisé peut appliquer un autre passage. Le résultat est une incohérence entre les journaux, l’entrée du gestionnaire et les appels de services en aval.

Où auditer en premier

  • règles de réécriture du proxy inverse
  • paramètres de normalisation CDN ou WAF
  • extraction des paramètres de route
  • helpers de redirection
  • constructeurs de requêtes des SDK tiers
  • filtres de sécurité personnalisés

Un court audit sur ces couches révèle généralement pourquoi une valeur a changé plus que prévu.

Conclusion

Le double encodage est rarement un mystère de bas niveau. C’est généralement un échec de coordination entre des couches qui essaient toutes d’aider avec la même URL. Le correctif consiste à traiter l’encodage comme une étape à responsabilité unique, à conserver les valeurs brutes en interne et à normaliser soigneusement en périphérie.

Lorsqu’une URL semble incorrecte, ne pas se contenter de la corriger avec un décodage supplémentaire. Retracer le chemin complet de la valeur : où elle a commencé, qui l’a encodée, qui l’a encodée à nouveau, et si le composant final était un chemin, une valeur de requête ou une URL imbriquée. Cette approche résout le bug sans créer un système plus fragile.