Skip to content

Dynamic Render Path警告の解消(Book.exist?の安全化) #1737

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 12, 2025

Conversation

nacchan99
Copy link
Contributor

@nacchan99 nacchan99 commented Aug 12, 2025

cf. #1727
cf. #1729
cf. #1736

config/brakeman.ignore に登録されていた Dynamic Render Path の警告を解消しました!

やったこと

  • Book.exist? メソッドで対象ディレクトリ内のファイル存在確認を行うよう修正
  • 不要となった SotechshaPagesController / Sotechsha2PagesController を削除
  • 解消済みの警告を .ignore から削除

- Book.exist? メソッドで対象ディレクトリ内のファイル存在確認を行うよう修正
- 不要となった SotechshaPagesController / Sotechsha2PagesController を削除
@yasulab
Copy link
Member

yasulab commented Aug 12, 2025

@claude Tell me detailed example stories of the Dynamic Render Path in this public Rails app?

Dynamic Render Path警告の解消(Book.exist?の安全化)

Copy link
Contributor

claude bot commented Aug 12, 2025

Claude finished @yasulab's task —— View job


Dynamic Render Path脆弱性の詳細な解説

このPRで解消されたDynamic Render Path脆弱性について、具体的な攻撃シナリオとともに説明します。

🚨 重大な問題 (セキュリティ、破壊的変更)

修正前の脆弱性パターン

1. 削除された脆弱なコントローラー

# app/controllers/sotechsha_pages_controller.rb (削除済み)
class SotechshaPagesController < ApplicationController
  def show
    render "sotechsha_pages/#{params[:page]}"  # ⚠️ 危険!
  end
end

2. 具体的な攻撃シナリオ

シナリオ1: ディレクトリトラバーサル攻撃

攻撃URL: /sotechsha/../../admin/secrets
↓
render "sotechsha_pages/../../admin/secrets"
↓
実際にレンダリング: app/views/admin/secrets.html.erb

攻撃者が params[:page]../../admin/secrets を注入すると、意図しないビューファイルがレンダリングされる可能性があります。

シナリオ2: 機密情報の露出

攻撃URL: /sotechsha2/../../../config/credentials
↓
render "sotechsha2_pages/../../../config/credentials"
↓
エラーメッセージから設定ファイルのパスが漏洩

シナリオ3: 内部構造の探索

# 攻撃者が以下のようなパスを試行
/sotechsha/../../../../app/models/user
/sotechsha/../../../../app/controllers/admin_controller
/sotechsha/../../../../config/database

エラーメッセージの違いから、存在するファイルと存在しないファイルを判別でき、アプリケーションの内部構造が露出する危険性があります。

3. Book.exist? の旧実装の問題

# 修正前のBook.exist?
def self.exist?(title, page)
  page.nil? ?
    self.find(title).any? :
    self.find(title).map(&:filename).include?(page + ".html")  # ⚠️ 不完全なチェック
end

この実装では、page パラメータに ../ などのディレクトリトラバーサル文字列が含まれていてもチェックされません。

✅ 良い実装 (参考になる箇所)

修正後の安全な実装

1. Book.exist? の改善版

# app/models/book.rb:21-30
def self.exist?(title, page)
  return false unless page.present?

  view_paths = [
    Rails.root.join("app/views/books/#{title}/#{page}.html.erb"),
    Rails.root.join("app/views/#{title}/#{page}.html.erb")
  ]

  view_paths.any? { |path| File.exist?(path) }
end

安全性のポイント:

  • Rails.root.join を使用して絶対パスを構築
  • ✅ 明示的に許可されたディレクトリのみをチェック
  • File.exist? で実際のファイル存在確認を実施
  • ✅ ディレクトリトラバーサル攻撃が無効化される

2. BooksController の安全な実装

# app/controllers/books_controller.rb:16-21
def render_book_page(params)
  book_title = params[:action].split('_').first
  Book.exist?(book_title, params[:page]) ?
    render("books/#{book_title}/#{params[:page]}") :
    redirect_to("/#{book_title}", flash: { warning: '該当するページが見つかりませんでした 💦'} )
end

攻撃シナリオに対する防御:

攻撃URL: /sotechsha/../../admin/secrets
↓
Book.exist?("sotechsha1", "../../admin/secrets")
↓
チェック対象パス:
- /home/runner/work/coderdojo.jp/coderdojo.jp/app/views/books/sotechsha1/../../admin/secrets.html.erb
- /home/runner/work/coderdojo.jp/coderdojo.jp/app/views/sotechsha1/../../admin/secrets.html.erb
↓
File.exist? = false (これらのパスは正規化されても意図した場所外)
↓
結果: リダイレクト(攻撃失敗)
💡 提案 (より良い実装方法)

さらなる安全性向上の提案

  1. パラメータのホワイトリスト化
ALLOWED_PAGES = %w[0 1 2 3 4 5 6 gazou].freeze

def self.exist?(title, page)
  return false unless ALLOWED_PAGES.include?(page)
  # ... 既存のチェック
end
  1. パスの正規化とサニタイゼーション
def self.exist?(title, page)
  return false unless page.present?
  
  # パスセパレータを含む場合は即座に拒否
  return false if page.include?('/') || page.include?('\\')
  
  # 既存のチェック...
end
  1. Content Security Policy (CSP) の設定
# config/application.rb
config.content_security_policy do |policy|
  policy.default_src :self
  # その他のCSP設定
end

まとめ

このPRは、Brakemanが検出したDynamic Render Path脆弱性を適切に解消しています。修正により:

  1. ディレクトリトラバーサル攻撃 が防止される
  2. 機密情報の露出リスク が排除される
  3. アプリケーション構造の探索 が不可能になる

Book.exist? メソッドの改善により、ユーザー入力を安全に検証してから render を実行するようになり、セキュリティが大幅に向上しました。

タスクリスト

  • PRの変更内容を確認
  • Dynamic Render Path脆弱性のパターンを分析
  • 具体的な攻撃シナリオを説明
  • 修正内容の効果を検証

@yasulab
Copy link
Member

yasulab commented Aug 12, 2025

@nacchan99 良さそうです! デプロイ後、念のため本番環境でも影響がおきてないかどうか該当ページをそれぞれ確認しておいてモラ会えると助かります! 🙏 ✨ cc/ @rakuda-san-desu

もし影響が出ていたらテストが抜け・漏れしているということなので、TDD で進めていただければ...!! (๑•̀ㅂ•́)و✨

@nacchan99
Copy link
Contributor Author

ご確認ありがとうございます!
マージします🚀

@nacchan99 nacchan99 merged commit 074d16b into main Aug 12, 2025
6 checks passed
@nacchan99 nacchan99 deleted the fix/brakeman-dynamic-render-path branch August 12, 2025 04:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants