Skip to content

Brakemanによる静的解析での脆弱性診断

概要

Webアプリケーションのセキュリティを確保することは、開発者にとって最も重要な責務の一つです。しかし、複雑なコードベースの中から、SQLインジェクション、クロスサイトスクリプティング(XSS)、マスアサインメントといった脆弱性を手動で見つけ出すのは非常に困難です。

Brakemanは、Railsアプリケーション専用に設計された静的解析セキュリティ脆弱性スキャナです。アプリケーションのソースコードを直接スキャンし、潜在的なセキュリティリスクを報告してくれます。コードを実行する必要がないため、開発の早い段階で、かつ網羅的に脆弱性をチェックできるのが大きな利点です。

この記事では、Brakemanの導入方法、基本的な使い方、そしてCI/CDパイプラインへの組み込みについて解説します。

Brakemanの導入

BrakemanはGemとして提供されています。Gemfile:developmentグループに追加するのが一般的です。

Gemfile

ruby
group :development do
  gem 'brakeman'
end

bundle installを実行してインストールします。

Brakemanの基本的な使い方

使い方は非常にシンプルです。Railsアプリケーションのルートディレクトリで、以下のコマンドを実行するだけです。

bash
$ brakeman

Brakemanはプロジェクトのコードをスキャンし、発見された脆弱性をレポートとして出力します。

レポートの例

+-----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Confidence | Category | Warning Type | Message | File | Line | Code |
+-----------------+-----------------+-----------------+-----------------+-----------------+-----------------+-----------------+-----------------+
| High | SQL Injection | SQL Injection | Possible SQL injection | app/controllers/users_controller.rb | 10 | User.where("name = '#{params[:name]}'") |
| Medium | Cross-Site Scripting | Unescaped Output | Unescaped parameter value | app/views/users/show.html.erb | 5 | <%= params[:name] %> |
+-----------------+-----------------+-----------------+-----------------+-----------------+-----------------+-----------------+

レポートには以下の情報が含まれます。

  • Confidence: 脆弱性である可能性の確信度(High, Medium, Low)。
  • Category: 脆弱性のカテゴリ(例: SQL Injection)。
  • Warning Type: 警告の種類。
  • Message: 警告メッセージ。
  • File: 問題が検出されたファイル。
  • Line: 問題があるコードの行番号。
  • Code: 該当するコードスニペット。

主な警告の種類

Brakemanが検出できる代表的な脆弱性は以下の通りです。

  • SQL Injection: ユーザー入力をSQLクエリに直接埋め込むことで、データベースを不正に操作される脆弱性。
  • Cross-Site Scripting (XSS): ユーザー入力をエスケープせずにHTMLに出力することで、悪意のあるスクリプトが実行される脆弱性。
  • Mass Assignment: update_attributesなどで、意図しない属性まで更新されてしまう脆弱性。
  • Command Injection: ユーザー入力をシェルコマンドに直接埋め込むことで、任意のコマンドが実行される脆弱性。
  • Redirect: ユーザー入力に基づいてリダイレクトを行う際に、外部の悪意のあるサイトに誘導される脆弱性。

レポートのフォーマット変更

デフォルトのコンソール出力以外にも、様々なフォーマットでレポートを出力できます。

  • HTMLレポート: -oオプションで出力ファイルを指定します。

    bash
    $ brakeman -o brakeman_report.html

    ブラウザで開ける見やすいレポートが生成されます。

  • JSONレポート:

    bash
    $ brakeman -o brakeman_report.json

    他のツールと連携させる場合に便利です。

偽陽性 (False Positive) の管理

静的解析ツールは、実際には脆弱性ではないコードを「脆弱性の可能性がある」と報告すること(偽陽性)があります。Brakemanには、これを管理するための仕組みがあります。

  1. インタラクティブな無視: -Iオプションを付けて実行すると、各警告に対して無視するかどうかを対話形式で選択できます。

    bash
    $ brakeman -I

    選択結果はconfig/brakeman.ignoreファイルに保存されます。

  2. 設定ファイルによる無視: config/brakeman.ignoreファイルが生成されたら、次回のスキャンからはこのファイルに記載された警告は無視されます。

    json
    {
      "ignored_warnings": [
        {
          "warning_type": "Cross-Site Scripting",
          "fingerprint": "...", // 警告を一意に識別するハッシュ
          "note": "This is intentionally unescaped for a specific reason."
        }
      ]
    }

    noteフィールドに無視する理由を記述しておくことが強く推奨されます。

CI/CDへの組み込み

Brakemanの真価は、CI/CDパイプラインに組み込み、コードがマージされる前に自動的に脆弱性スキャンを実行することで発揮されます。

GitHub Actionsでの実行例

yaml
# .github/workflows/security.yml

name: Security Scan

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  brakeman:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3

    - name: Set up Ruby
      uses: ruby/setup-ruby@v1
      with:
        ruby-version: '3.2' # プロジェクトのRubyバージョンに合わせる
        bundler-cache: true

    - name: Run Brakeman
      run: bundle exec brakeman --exit-on-warn --no-progress
  • --exit-on-warn: 何か一つでも警告(無視していないもの)があれば、0以外のステータスコードで終了します。これにより、CIのジョブが失敗し、脆弱性のあるコードのマージを防ぎます。

まとめ

Brakemanは、Rails開発におけるセキュリティのベースラインを確保するための非常に強力なツールです。

  • 手軽さ: コマンド一つで簡単に実行できる。
  • 網羅性: Rails特有の脆弱性を幅広くカバーしている。
  • 自動化: CI/CDに組み込むことで、継続的な脆弱性スキャンを実現できる。

もちろん、Brakemanが全ての脆弱性を発見できるわけではありません。しかし、多くの一般的なセキュリティリスクを開発の初期段階で、かつ自動的に検出してくれることは、開発者にとって大きな助けとなります。安全なRailsアプリケーションを構築するために、ぜひBrakemanを開発プロセスに取り入れてください。

AI が自動生成した技術記事をまとめたテックブログ