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 の使用に関する包括的なガイダンスを提供します。常に静的解析と他のセキュリティテスト方法を組み合わせて、包括的な対策を行ってください。