flawopen.com/path-traversal/Ruby

● CWE-918 · Haute
Recherche · FlawOpen

Path Traversal in Ruby

How File.join in Ruby leaves relative paths unresolved, and how to verify boundaries using File.expand_path.

💡 Explication en Langage Simple (ELI5)

Imaginez un lecteur de carte d'hôtel programmé pour n'ouvrir que les chambres du 2e étage. Si un client tape '../../master-safe' sur le digicode, la serrure vulnérable remonte le couloir et déverrouille le coffre-fort principal du gérant.

Concepts Clés et Termes

Web Application Security
Composant d'architecture clé affecté par CWE-918.
CWE-918
Classification standard Common Weakness Enumeration (CWE) pour path-traversal-ruby.
Defense-in-Depth
Vérification d'ingénierie multicouche et isolation des limites à l'exécution.

Déroulement de l'Attaque Étape par Étape

Step 1

Saisie de Chemin de Fichier par le Client

Un point de terminaison accepte un nom de fichier ou un identifiant de ressource via un paramètre HTTP.

Step 2

Injection de Séquence de Traversée de Répertoire

L'attaquant injecte des séquences relatives comme '../', '..%2f' ou des chemins absolus non autorisés.

Step 3

Contournement de la Limite du Système de Fichiers

Le backend concatène naïvement le fichier sans vérifier le chemin canonique ni restreindre le répertoire racine.

Step 4

Divulgation ou Écriture Arbitraire de Fichiers

Le runtime ouvre et renvoie des fichiers système critiques (/etc/passwd, secrets d'API) à l'attaquant.

Code Source : Vulnérable vs Sécurisé

✕ IMPLÉMENTATION VULNÉRABLE
# VULNERABLE: File.join does not resolve traversal dots
class DownloadsController < ApplicationController
  BASE_DIR = Rails.root.join('storage', 'public').to_s

  def show
    # Attacker input: "../../config/master.key"
    file_path = File.join(BASE_DIR, params[:file])
    
    # Leaks private Rails master encryption key!
    send_file file_path
  end
end
✓ PATCH SÉCURISÉ ET ROBUSTE
# HARDENED: Canonicalize with File.realpath and enforce prefix
class DownloadsController < ApplicationController
  BASE_DIR = File.realpath(Rails.root.join('storage', 'public').to_s)

  def show
    user_file = params[:file].to_s
    return head :bad_request if user_file.blank?

    # 1. Expand path relative to BASE_DIR
    target_path = File.expand_path(user_file, BASE_DIR)

    # 2. Strict boundary check with trailing separator
    allowed_prefix = BASE_DIR.end_with?('/') ? BASE_DIR : "#{BASE_DIR}/"
    unless target_path.start_with?(allowed_prefix)
      return render plain: 'Forbidden: Path Traversal detected', status: :forbidden
    end

    return head :not_found unless File.file?(target_path)

    send_file target_path
  end
end

Liste de Contrôle de Sécurité pour l'Ingénierie

References