FlawOpen

flawopen.com/Path traversal/Python os.path.join()

os.path.join() empêche-t-il le path traversal ?

CWE-22: Path TraversalPage de référence
Réponse courte

Non. Imaginez la base comme une pièce : .. traverse les pièces parentes ; un chemin absolu est une nouvelle adresse qui fait abandonner la pièce initiale à os.path.join(). Résolvez le chemin final et vérifiez qu’il reste dans le répertoire autorisé avant de l’ouvrir.

VULNERABLE
import os

base_dir = "/srv/uploads"
user_filename = "../../outside/demo.txt"
path = os.path.join(base_dir, user_filename)
# Relative traversal can leave the base.

path = os.path.join(base_dir, "/outside/demo.txt")
# An absolute segment discards base_dir.
SECURE — resolve and check containment
import os

def resolve_under_base(base_dir, user_filename):
    if not isinstance(user_filename, str) or not user_filename:
        raise ValueError("Invalid filename")

    base = os.path.realpath(base_dir)
    candidate = os.path.realpath(
        os.path.join(base, user_filename)
    )

    try:
        inside = os.path.commonpath((base, candidate)) == base
    except ValueError:  # e.g. different Windows drives
        inside = False

    if not inside or candidate == base:
        raise ValueError("Invalid filename")
    return candidate

Deux comportements de jonction à prendre en compte

.. peut faire sortir un chemin relatif du répertoire prévu. La documentation Python précise qu’un chemin absolu fait ignorer les composants précédents ; sous Windows, les règles de lecteur et de racine diffèrent de POSIX. pathlib.Path(base) / user_input agit pareil. Ni jonction ni normalisation ne vérifie l’autorisation.

Pourquoi commonpath() est plus sûr que les préfixes

Résolvez la base de confiance et le candidat avant comparaison. os.path.commonpath() compare les composants, pas les préfixes de caractères, et lève ValueError si lecteurs ou racines sont incompatibles ; rejetez ces cas. realpath() résout les liens présents au contrôle, mais ne bloque pas leur remplacement avant l’ouverture. Si des tiers peuvent modifier l’arborescence, utilisez des descripteurs et des contrôles no-follow adaptés.

Questions fréquentes

pathlib se comporte-t-il pareil ?

Oui. L’opérateur / de Path ignore les composants précédents si le chemin suivant est absolu. Résolvez le résultat et vérifiez qu’il reste dans la base autorisée.

realpath() élimine-t-il les courses ?

Non. Il résout les liens présents lors de la validation ; un autre processus peut les modifier avant l’ouverture. Limitez les écritures ou utilisez des opérations relatives à un descripteur avec no-follow si disponible.

Références

À voir aussi Traversée de répertoires (CWE-22) : fonctionnement et prévention dans tous les langages — flawopen.com Qu’est-ce qu’une vulnérabilité Zip Slip ? Node.js path.join() ne bloque pas Path Traversal PHP include() et chemins contrôlés par l’utilisateur