Saltar a contenido

Brakeman Ruby on Rails Security Scanner Cheat Sheet

"Clase de la hoja" idbutton id="brakeman-copy-btn" class="copy-btn" onclick="copyAllCommands()" Copiar todos los comandos id="brakeman-pdf-btn" class="pdf-btn" onclick="generatePDF()" Generar PDF seleccionado/button ■/div titulada

Sinopsis

Brakeman es un escáner de seguridad de análisis estático diseñado específicamente para aplicaciones Ruby en Rails. Analiza el código de aplicación Rails para encontrar vulnerabilidades de seguridad sin requerir que la aplicación se ejecute. Brakeman es una herramienta esencial en los oleoductos DevSecOps para aplicaciones Rails, ayudando a los desarrolladores a identificar problemas comunes de seguridad como inyección SQL, scripting cross-site (XSS), y otras vulnerabilidades específicas de Rails temprano en el proceso de desarrollo.

NOVEDAD Nota: Brakeman está diseñado específicamente para Ruby en aplicaciones Rails y puede no funcionar correctamente con otros marcos de Ruby. Debe utilizarse como parte de una estrategia integral de pruebas de seguridad.

Instalación

Usando gema

# Install Brakeman gem
gem install brakeman

# Install specific version
gem install brakeman -v 5.4.1

# Install from source
git clone https://github.com/presidentbeef/brakeman.git
cd brakeman
gem build brakeman.gemspec
gem install brakeman-*.gem

# Verify installation
brakeman --version

Usando Bundler

# Add to Gemfile
group :development do
  gem 'brakeman', require: false
end

# Install
bundle install

# Run via bundle
bundle exec brakeman

Usando Docker

# Pull official Brakeman image
docker pull presidentbeef/brakeman

# Run Brakeman in container
docker run --rm -v $(pwd):/code presidentbeef/brakeman

# Build custom image
cat > Dockerfile ``<< 'EOF'
FROM ruby:3.0-slim
RUN gem install brakeman
WORKDIR /app
ENTRYPOINT ["brakeman"]
EOF

docker build -t custom-brakeman .
docker run --rm -v $(pwd):/app custom-brakeman

Administradores de paquetes

# Ubuntu/Debian (via RubyGems)
sudo apt update
sudo apt install ruby-dev
sudo gem install brakeman

# macOS with Homebrew
brew install brakeman

# CentOS/RHEL/Fedora
sudo dnf install ruby-devel
sudo gem install brakeman

Uso básico

Escáneos simples

# Scan current Rails application
brakeman

# Scan specific Rails application
brakeman /path/to/rails/app

# Scan with verbose output
brakeman -v

# Scan with debug output
brakeman -d

# Quick scan (faster, less thorough)
brakeman -q

# Scan specific files
brakeman --only-files app/controllers/users_controller.rb,app/models/user.rb

Formatos de salida

# Default text output
brakeman

# JSON output
brakeman -f json

# HTML output
brakeman -f html

# CSV output
brakeman -f csv

# Markdown output
brakeman -f markdown

# SARIF output (for GitHub integration)
brakeman -f sarif

# Save output to file
brakeman -o brakeman-report.html -f html
brakeman -o brakeman-report.json -f json
brakeman -o brakeman-report.csv -f csv

Niveles de confianza

# Show only high confidence warnings
brakeman -w3

# Show high and medium confidence warnings
brakeman -w2

# Show all warnings (including low confidence)
brakeman -w1

# Default behavior (medium and high confidence)
brakeman

Configuración

Archivo de configuración (.brakeman.yml)

# .brakeman.yml
:app_path: "."
:output_files:
  - "brakeman-report.html"
  - "brakeman-report.json"
:output_formats:
  - :html
  - :json
:quiet: false
:min_confidence: 2
:combine_locations: true
:collapse_mass_assignment: true
:highlight_user_input: true
:ignore_redirect_to_model: true
:ignore_model_output: false
:check_arguments: true
:safe_methods:
  - :sanitize
  - :h
  - :html_escape
:skip_checks:
  - :SSL
  - :LinkTo
:report_progress: true
:parallel_checks: true

Configuración de línea de comandos

# Set minimum confidence level
brakeman --confidence-level 2  # Medium and high only
brakeman --confidence-level 3  # High only

# Skip specific checks
brakeman --skip-checks SSL,LinkTo,Render

# Run only specific checks
brakeman --test SQL,XSS,Command

# Ignore specific files
brakeman --skip-files app/controllers/admin_controller.rb

# Set Rails version explicitly
brakeman --rails3
brakeman --rails4
brakeman --rails5
brakeman --rails6
brakeman --rails7

# Additional options
brakeman --no-progress        # Disable progress reporting
brakeman --no-pager          # Disable pager for output
brakeman --table-width 120   # Set table width
brakeman --url-safe-methods method1,method2  # Additional URL-safe methods

Uso avanzado

Escáner de referencia y progresivo

# Create baseline
brakeman -f json -o baseline.json

# Compare against baseline
brakeman --compare baseline.json

# Ignore baseline warnings
brakeman --ignore-config baseline.ignore

# Generate ignore file from current warnings
brakeman --ignore-config brakeman.ignore --interactive-ignore

Comprobaciones personalizadas

# custom_check.rb
class CustomCheck < Brakeman::BaseCheck
  Brakeman::Checks.add self

  @description = "Check for custom security pattern"

  def run_check
    tracker.find_call(:target =>`` nil, :method => :dangerous_method).each do|result|
      warn :result => result,
           :warning_type => "Custom Warning",
           :warning_code => :custom_dangerous_method,
           :message => "Avoid using dangerous_method",
           :confidence => :high
    end
  end
end

Integración con velas

# config/brakeman.yml in Rails app
:app_path: "."
:output_files:
  - "tmp/brakeman-report.html"
:output_formats:
  - :html
:quiet: true
:min_confidence: 2

# Rake task integration
# lib/tasks/security.rake
namespace :security do
  desc "Run Brakeman security scan"
  task :scan do
    require 'brakeman'

    options = \\\\{
      :app_path => Rails.root.to_s,
      :output_formats => [:html, :json],
      :output_files => [
        Rails.root.join('tmp', 'brakeman-report.html').to_s,
        Rails.root.join('tmp', 'brakeman-report.json').to_s
      ],
      :quiet => false,
      :min_confidence => 2
    \\\\}

    tracker = Brakeman.run(options)

    if tracker.warnings.any?
      puts "Security warnings found! Check tmp/brakeman-report.html"
      exit 1
    else
      puts "No security warnings found."
    end
  end
end

CI/CD Integration

GitHub Actions

# .github/workflows/security.yml
name: Security Scan

on: [push, pull_request]

jobs:
  brakeman:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3

    - name: Set up Ruby
      uses: ruby/setup-ruby@v1
      with:
        ruby-version: '3.0'
        bundler-cache: true

    - name: Install Brakeman
      run: gem install brakeman

    - name: Run Brakeman
      run: brakeman -f sarif -o brakeman-results.sarif

    - name: Upload SARIF file
      uses: github/codeql-action/upload-sarif@v2
      with:
        sarif_file: brakeman-results.sarif

    - name: Upload results
      uses: actions/upload-artifact@v3
      with:
        name: brakeman-report
        path: brakeman-results.sarif

GitLab CI

# .gitlab-ci.yml
stages:
  - security

brakeman:
  stage: security
  image: ruby:3.0
  before_script:
    - gem install brakeman
  script:
    - brakeman -f json -o brakeman-report.json
  artifacts:
    reports:
      sast: brakeman-report.json
    paths:
      - brakeman-report.json
    expire_in: 1 week
  allow_failure: true

Jenkins Pipeline

// Jenkinsfile
pipeline \\\\{
    agent any

    stages \\\\{
        stage('Security Scan') \\\\{
            steps \\\\{
                script \\\\{
                    sh 'gem install brakeman'
                    sh 'brakeman -f json -o brakeman-report.json'
                    sh 'brakeman -f html -o brakeman-report.html'
                \\\\}
            \\\\}
            post \\\\{
                always \\\\{
                    archiveArtifacts artifacts: 'brakeman-report.*', fingerprint: true
                    publishHTML([
                        allowMissing: false,
                        alwaysLinkToLastBuild: true,
                        keepAll: true,
                        reportDir: '.',
                        reportFiles: 'brakeman-report.html',
                        reportName: 'Brakeman Security Report'
                    ])
                \\\\}
                failure \\\\{
                    emailext (
                        subject: "Security Scan Failed: $\\\\{env.JOB_NAME\\\\} - $\\\\{env.BUILD_NUMBER\\\\}",
                        body: "Brakeman found security issues. Check the report for details.",
                        to: "$\\\\{env.CHANGE_AUTHOR_EMAIL\\\\}"
                    )
                \\\\}
            \\\\}
        \\\\}
    \\\\}
\\\\}

CircleCI

# .circleci/config.yml
version: 2.1

jobs:
  security_scan:
    docker:
      - image: cimg/ruby:3.0
    steps:
      - checkout
      - run:
          name: Install Brakeman
          command: gem install brakeman
      - run:
          name: Run Brakeman
          command:|
            brakeman -f json -o brakeman-report.json
            brakeman -f html -o brakeman-report.html
      - store_artifacts:
          path: brakeman-report.html
      - store_artifacts:
          path: brakeman-report.json

workflows:
  version: 2
  security:
    jobs:
      - security_scan

Vulnerabilidad común Patrones

SQL Injection

# BAD: String interpolation in queries
User.where("name = '#\\\\{params[:name]\\\\}'")
User.find_by_sql("SELECT * FROM users WHERE id = #\\\\{params[:id]\\\\}")

# GOOD: Parameterized queries
User.where(name: params[:name])
User.where("name = ?", params[:name])
User.find_by_sql(["SELECT * FROM users WHERE id = ?", params[:id]])

Scripting cruzado (XSS)

<%= params[:message] %>
<%= raw user_input %>
<%= content.html_safe %>

<%= h(params[:message]) %>
<%= sanitize(user_input) %>
<%= simple_format(content) %>

Asignación masiva

# BAD: Unfiltered parameters
User.create(params[:user])
user.update_attributes(params[:user])

# GOOD: Strong parameters
def user_params
  params.require(:user).permit(:name, :email)
end

User.create(user_params)
user.update_attributes(user_params)

Inyección de comandos

# BAD: Unescaped system calls
system("ls #\\\\{params[:directory]\\\\}")
`grep #\\{params[:pattern]\\} file.txt`

# GOOD: Escaped or parameterized calls
system("ls", params[:directory])
Open3.capture3("grep", params[:pattern], "file.txt")

Cross-Site Request Forgery (CSRF)

# BAD: Missing CSRF protection
class ApplicationController ``< ActionController::Base
  # protect_from_forgery commented out
end

# GOOD: CSRF protection enabled
class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
end

Automatización y scripting

Escáner de seguridad automatizado

#!/usr/bin/env ruby
# brakeman_scanner.rb

require 'brakeman'
require 'json'
require 'optparse'

class BrakemanScanner
  def initialize(app_path, options = \\\{\\\})
    @app_path = app_path
    @options = \\\{
      app_path: app_path,
      quiet: true,
      min_confidence: 2,
      output_formats: [:json, :html],
      output_files: [
        File.join(app_path, 'tmp', 'brakeman-report.json'),
        File.join(app_path, 'tmp', 'brakeman-report.html')
      ]
    \\\}.merge(options)
  end

  def run_scan
    puts "Running Brakeman scan on #\\\{@app_path\\\}..."

    begin
      @tracker = Brakeman.run(@options)
      generate_summary
      return @tracker.warnings.empty?
    rescue =>`` e
      puts "Error running Brakeman: #\\\\{e.message\\\\}"
      return false
    end
  end

  def generate_summary
    warnings = @tracker.warnings

    puts "\n=== Brakeman Security Scan Summary ==="
    puts "Total warnings: #\\\\{warnings.length\\\\}"

    # Group by confidence
    by_confidence = warnings.group_by(&:confidence)
    puts "High confidence: #\\\\{(by_confidence[:high]||[]).length\\\\}"
    puts "Medium confidence: #\\\\{(by_confidence[:medium]||[]).length\\\\}"
    puts "Low confidence: #\\\\{(by_confidence[:low]||[]).length\\\\}"

    # Group by warning type
    by_type = warnings.group_by(&:warning_type)
    puts "\nWarnings by type:"
    by_type.each do|type, type_warnings|
      puts "  #\\\\{type\\\\}: #\\\\{type_warnings.length\\\\}"
    end

    # Show high confidence warnings
    high_warnings = by_confidence[:high]||[]
    if high_warnings.any?
      puts "\n=== High Confidence Warnings ==="
      high_warnings.each do|warning|
        puts "#\\\\{warning.file\\\\}:#\\\\{warning.line\\\\} - #\\\\{warning.warning_type\\\\}: #\\\\{warning.message\\\\}"
      end
    end
  end

  def save_baseline
    baseline_file = File.join(@app_path, 'brakeman.baseline')
    File.write(baseline_file, @tracker.warnings.to_json)
    puts "Baseline saved to #\\\\{baseline_file\\\\}"
  end

  def compare_with_baseline
    baseline_file = File.join(@app_path, 'brakeman.baseline')
    return unless File.exist?(baseline_file)

    baseline_warnings = JSON.parse(File.read(baseline_file))
    current_warnings = @tracker.warnings.map(&:to_hash)

    new_warnings = current_warnings - baseline_warnings
    fixed_warnings = baseline_warnings - current_warnings

    puts "\n=== Baseline Comparison ==="
    puts "New warnings: #\\\\{new_warnings.length\\\\}"
    puts "Fixed warnings: #\\\\{fixed_warnings.length\\\\}"

    if new_warnings.any?
      puts "\nNew warnings found:"
      new_warnings.each do|warning|
        puts "  #\\\\{warning['file']\\\\}:#\\\\{warning['line']\\\\} - #\\\\{warning['warning_type']\\\\}"
      end
    end
  end
end

# Command line interface
options = \\\\{\\\\}
OptionParser.new do|opts|
  opts.banner = "Usage: #\\\\{$0\\\\} [options] [app_path]"

  opts.on("-c", "--confidence LEVEL", Integer, "Minimum confidence level (1-3)") do|c|
    options[:min_confidence] = c
  end

  opts.on("-q", "--quiet", "Quiet mode") do
    options[:quiet] = true
  end

  opts.on("-b", "--baseline", "Save current scan as baseline") do
    options[:save_baseline] = true
  end

  opts.on("--compare", "Compare with baseline") do
    options[:compare_baseline] = true
  end

  opts.on("-h", "--help", "Show this help") do
    puts opts
    exit
  end
end.parse!

app_path = ARGV[0]||Dir.pwd

scanner = BrakemanScanner.new(app_path, options)
success = scanner.run_scan

if options[:save_baseline]
  scanner.save_baseline
end

if options[:compare_baseline]
  scanner.compare_with_baseline
end

exit(success ? 0 : 1)

Batch Processing Script

#!/bin/bash
# batch_brakeman_scan.sh

# Configuration
RAILS_APPS_DIR="/path/to/rails/apps"
REPORTS_DIR="/path/to/reports"
DATE=$(date +%Y%m%d_%H%M%S)

# Create reports directory
mkdir -p "$REPORTS_DIR"

# Function to scan Rails app
scan_rails_app() \\\\{
    local app_path="$1"
    local app_name=$(basename "$app_path")
    local report_file="$REPORTS_DIR/$\\\\{app_name\\\\}_$\\\\{DATE\\\\}.json"
    local html_report="$REPORTS_DIR/$\\\\{app_name\\\\}_$\\\\{DATE\\\\}.html"

    echo "Scanning $app_name..."

    # Check if it's a Rails app
    if [ ! -f "$app_path/config/application.rb" ]; then
        echo "Skipping $app_name - not a Rails application"
        return
    fi

    # Run Brakeman scan
    cd "$app_path"
    brakeman -f json -o "$report_file" -q
    brakeman -f html -o "$html_report" -q

    # Check for high confidence warnings
    high_warnings=$(jq '[.warnings[]|select(.confidence == "High")]|length' "$report_file" 2>/dev/null||echo "0")

    if [ "$high_warnings" -gt 0 ]; then
        echo "WARNING: $app_name has $high_warnings high confidence warnings!"
        echo "$app_name" >> "$REPORTS_DIR/high_risk_apps.txt"
    fi

    echo "Scan completed for $app_name"
\\\\}

# Find and scan all Rails applications
find "$RAILS_APPS_DIR" -name "application.rb" -path "*/config/*"|while read -r config_file; do
    app_dir=$(dirname "$(dirname "$config_file")")
    scan_rails_app "$app_dir"
done

echo "Batch scanning completed. Reports saved to $REPORTS_DIR"

# Generate summary report
echo "=== Batch Scan Summary ===" > "$REPORTS_DIR/summary_$\\\\{DATE\\\\}.txt"
echo "Scan Date: $(date)" >> "$REPORTS_DIR/summary_$\\\\{DATE\\\\}.txt"
echo "Total applications scanned: $(find "$REPORTS_DIR" -name "*_$\\\\{DATE\\\\}.json"|wc -l)" >> "$REPORTS_DIR/summary_$\\\\{DATE\\\\}.txt"

if [ -f "$REPORTS_DIR/high_risk_apps.txt" ]; then
    echo "High risk applications: $(wc -l < "$REPORTS_DIR/high_risk_apps.txt")" >> "$REPORTS_DIR/summary_$\\\\{DATE\\\\}.txt"
    echo "" >> "$REPORTS_DIR/summary_$\\\\{DATE\\\\}.txt"
    echo "High risk applications:" >> "$REPORTS_DIR/summary_$\\\\{DATE\\\\}.txt"
    cat "$REPORTS_DIR/high_risk_apps.txt" >> "$REPORTS_DIR/summary_$\\\\{DATE\\\\}.txt"
fi

Integración con Herramientas de Desarrollo

VS Code Integration

// .vscode/tasks.json
\\\\{
    "version": "2.0.0",
    "tasks": [
        \\\\{
            "label": "Brakeman Security Scan",
            "type": "shell",
            "command": "brakeman",
            "args": ["-f", "html", "-o", "tmp/brakeman-report.html"],
            "group": "test",
            "presentation": \\\\{
                "echo": true,
                "reveal": "always",
                "focus": false,
                "panel": "shared"
            \\\\},
            "problemMatcher": []
        \\\\}
    ]
\\\\}

// .vscode/settings.json
\\\\{
    "ruby.lint": \\\\{
        "brakeman": \\\\{
            "enable": true,
            "command": "brakeman"
        \\\\}
    \\\\}
\\\\}

Integración RubyMine

# External tool configuration
# Program: brakeman
# Arguments: -f html -o $ProjectFileDir$/tmp/brakeman-report.html
# Working directory: $ProjectFileDir$

Integración de guardias

# Guardfile
guard :brakeman, :run_on_start => true do
  watch(%r\\\\{^app/.+\.(rb|erb)$\\\\})
  watch(%r\\\\{^config/.+\.rb$\\\\})
  watch(%r\\\\{^lib/.+\.rb$\\\\})
  watch('Gemfile')
end

Buenas prácticas

Configuration Management

# .brakeman.yml - Production configuration
:app_path: "."
:output_files:
  - "tmp/brakeman-report.html"
  - "tmp/brakeman-report.json"
:output_formats:
  - :html
  - :json
:quiet: false
:min_confidence: 2
:combine_locations: true
:collapse_mass_assignment: true
:highlight_user_input: true
:ignore_redirect_to_model: true
:ignore_model_output: false
:check_arguments: true
:safe_methods:
  - :sanitize
  - :h
  - :html_escape
  - :simple_format
:skip_checks: []
:report_progress: true
:parallel_checks: true
:absolute_paths: false
:summary_only: false

Ignorar la gestión de archivos

# brakeman.ignore
---
:ignored_warnings:
- :warning_type: SQL
  :fingerprint: 1234567890abcdef
  :note: "Reviewed and accepted - admin only functionality"
- :warning_type: CrossSiteScripting
  :fingerprint: abcdef1234567890
  :note: "False positive - output is properly sanitized"

Flujo de trabajo del equipo

# Makefile integration
.PHONY: security-scan
security-scan:
    @echo "Running Brakeman security scan..."
    @brakeman -q -f json -o tmp/brakeman-report.json
    @if [ -s tmp/brakeman-report.json ]; then \
        echo "Security warnings found! Check tmp/brakeman-report.html"; \
        brakeman -f html -o tmp/brakeman-report.html; \
        exit 1; \
    else \
        echo "No security warnings found."; \
    fi

.PHONY: security-baseline
security-baseline:
    @echo "Creating security baseline..."
    @brakeman -f json -o brakeman.baseline
    @echo "Baseline created. Commit brakeman.baseline to version control."

# Pre-commit hook
#!/bin/bash
# .git/hooks/pre-commit
echo "Running Brakeman security scan..."
brakeman -q --no-pager
if [ $? -ne 0 ]; then
    echo "Security issues found. Commit aborted."
    echo "Run 'brakeman' to see details or 'brakeman -I' to ignore warnings."
    exit 1
fi

Solución de problemas

Cuestiones comunes

# Issue: Brakeman not detecting Rails app
# Solution: Ensure you're in Rails root directory
cd /path/to/rails/app
ls config/application.rb  # Should exist

# Issue: Too many false positives
# Solution: Use ignore file and tune confidence levels
brakeman --confidence-level 3  # High confidence only
brakeman -I  # Interactive ignore mode

# Issue: Performance issues with large apps
# Solution: Use parallel processing and skip unnecessary checks
brakeman --parallel-checks --skip-checks Render,LinkTo

# Issue: Integration with CI/CD failing
# Solution: Use appropriate exit codes and formats
brakeman -q -f json -o results.json||true

Optimización del rendimiento

# Skip time-consuming checks
brakeman --skip-checks Render,LinkTo,DetailedExceptions

# Use parallel processing
brakeman --parallel-checks

# Scan only specific directories
brakeman --only-files app/controllers/,app/models/

# Quick scan mode
brakeman -q --faster

Debugging

# Debug mode
brakeman -d

# Verbose output
brakeman -v

# Show timing information
brakeman --timing

# Test specific warning types
brakeman --test SQL,XSS

Recursos

-...

*Esta hoja de trampa proporciona una guía completa para usar Brakeman para identificar vulnerabilidades de seguridad en Ruby en aplicaciones Rails. Combina siempre el análisis estático con otros métodos de pruebas de seguridad para una cobertura integral. *