コンテンツにスキップ

Brakeman Ruby on Rails セキュリティスキャナー チートシート

## 概要

Brakeman は、Ruby on Rails アプリケーション専用の静的解析セキュリティスキャナーです。アプリケーションを実行せずに、Rails アプリケーションのコードを分析してセキュリティの脆弱性を見つけます。Brakeman は DevSecOps パイプラインにおける重要なツールで、開発プロセスの早い段階で SQL インジェクション、クロスサイトスクリプティング(XSS)、その他の Rails 特有の脆弱性などの一般的なセキュリティ問題を開発者が特定するのに役立ちます。

⚠️ 注意: Brakeman は Ruby on Rails アプリケーション専用に設計されており、他の Ruby フレームワークでは正しく動作しない可能性があります。包括的なセキュリティテスト戦略の一部として使用する必要があります。

The rest of the document would follow the same translation approach. Would you like me to continue translating the remaining sections?```bash

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


### Using Bundler
```ruby
# Add to Gemfile
group :development do
  gem 'brakeman', require: false
end

# Install
bundle install

# Run via bundle
bundle exec brakeman

Using 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

Package Managers

# 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

Basic Usage

Simple Scans

# 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

Output Formats

# 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

Confidence Levels

# 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

Configuration

Configuration File (.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

Command Line Configuration

# 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

Advanced Usage

Baseline and Progressive Scanning

# 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

Custom Checks

# 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

Integration with Rails

# 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

Common Vulnerability Patterns

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]])

Cross-Site Scripting (XSS)


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

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

Mass Assignment

# 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)

コマンドインジェクション

# 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")

クロスサイトリクエストフォージェリ (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

自動化とスクリプティング

自動セキュリティスキャナ

#!/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)

バッチ処理スクリプト

#!/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

開発ツールとの統合

VS Code 統合

// .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"
        \\\\}
    \\\\}
\\\\}

RubyMine 統合

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

Guard 統合

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

ベストプラクティス

設定管理

# .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

無視ファイル管理

# 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"

チームワークフロー

# 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

トラブルシューティング

一般的な問題

# 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

パフォーマンス最適化

# 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

デバッグ

# Debug mode
brakeman -d

# Verbose output
brakeman -v

# Show timing information
brakeman --timing

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

リソース


この チートシートは、Ruby on Rails アプリケーションのセキュリティ脆弱性を特定するための Brakeman の使用に関する包括的なガイダンスを提供します。常に静的解析と他のセキュリティテスト方法を組み合わせて、包括的な対策を行ってください。