flawopen.com/path-traversal/Ruby

● CWE-918 · Alta
Pesquisa · FlawOpen

Path Traversal in Ruby

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

💡 Explicação em Linguagem Simples (ELI5)

Imagine um scanner de chave de hotel que só deveria abrir quartos no segundo andar. Se um hóspede digita '../../master-safe' no teclado da porta, uma fechadura vulnerável sobe pelo corredor e abre o cofre principal da gerência.

Conceitos Centrais e Termos

Web Application Security
Componente de arquitetura principal afetado pelo CWE-918.
CWE-918
Classificação padrão Common Weakness Enumeration (CWE) para path-traversal-ruby.
Defense-in-Depth
Verificação de engenharia em múltiplas camadas e isolamento de limites em tempo de execução.

Fluxo de Ataque Passo a Paso

Step 1

Entrada de Caminho de Arquivo do Cliente

Um endpoint aceita um nome de arquivo ou identificador de recurso fornecido pelo usuário por parâmetro HTTP.

Step 2

Injeção de Sequência de Travessia

O invasor injeta sequências de diretório relativo como '../', '..%2f' ou caminhos absolutos no parâmetro.

Step 3

Violação do Limite do Sistema de Arquivos

O backend concatena o nome sem resolver o caminho canônico nem validar que o destino permaneça no diretório base.

Step 4

Divulgação ou Sobrescrita Arbitrária de Arquivos

O runtime abre e transmite arquivos sensíveis do sistema (como /etc/passwd ou credenciais) diretamente ao cliente.

Código-Fonte: Vulnerável vs. Seguro

✕ IMPLEMENTAÇÃO VULNERÁVEL
# 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 SEGURO E ROBUSTO
# 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

Lista de Verificação de Segurança para Engenharia

References