nebino

Path traversal : comprendre l’attaque et s’en protéger

20 octobre 2026

Une application qui construit un chemin de fichier à partir d’une donnée fournie par l’utilisateur peut être poussée à lire des fichiers qu’elle ne devait jamais exposer. C’est le path traversal.

Le principe

Imaginons une page de téléchargement qui lit un fichier dont le nom vient de l’adresse : /download?file=report.pdf. Si le code se contente de coller ce nom derrière un dossier, un visiteur peut envoyer ../../etc/passwd. Chaque ../ remonte d’un dossier, et le programme sort de l’espace qui lui était réservé.

L’attaque ne se limite pas à la lecture : selon le code, elle peut aussi permettre d’écrire ou de supprimer des fichiers, par exemple lors d’un envoi de fichier dont le nom est contrôlé par l’utilisateur.

Les variantes qui contournent les filtres naïfs

  • L’encodage : %2e%2e%2f pour ../, ou un double encodage comme %252e%252e%252f quand l’entrée est décodée deux fois.
  • Le séparateur Windows ..\, accepté par certains systèmes en plus de /.
  • Un chemin absolu comme /etc/passwd, qui ignore le dossier de base.
  • Une suppression maladroite de ../ : ....// redonne ../ une fois le filtre passé.

Se protéger

  • Ne jamais construire un chemin à partir d’une entrée brute. Préférer un identifiant (un nombre, un jeton) qui renvoie à un fichier connu grâce à une table de correspondance.
  • À défaut, normaliser puis vérifier : résoudre le chemin complet, liens symboliques compris, et contrôler qu’il reste sous le dossier autorisé.
  • Préférer une allowlist (caractères et extensions permis) à une denylist.
  • Appliquer le principe de least privilege : processus aux droits minimaux, conteneur ou chroot, système de fichiers en lecture seule quand c’est possible.
from pathlib import Path

BASE = Path("/srv/files").resolve()

def open_file(name):
    path = (BASE / name).resolve()
    if not path.is_relative_to(BASE):
        raise PermissionError("forbidden path")
    return path.open("rb")

Le point clé : on vérifie le chemin après résolution, jamais la chaîne d’origine.

Et pour un site statique ?

Un site composé uniquement de fichiers HTML, CSS et JavaScript n’a pas de code serveur qui lit des chemins : le risque vient surtout de la configuration. Les serveurs web courants refusent déjà de sortir de la racine du site, mais on peut renforcer en rejetant toute requête brute contenant ../ ou ses variantes encodées, en désactivant le directory listing et en masquant les fichiers cachés comme .git.

Le risque réapparaît dès qu’on ajoute un script, par exemple un formulaire de contact en PHP : les règles ci-dessus s’appliquent alors.

Voir aussi : hardening d’un serveur Debian, la plateforme de documents, qui gère des fichiers côté serveur

Sources

Retour au blog