Rubyでのセキュアプログラミングは「危険な入力をそのまま使わない」「OSやDBに渡すときは安全な経路を使う」が基本です。
よくある脆弱パターンと安全な書き方を対比でいくつか示します。
■ 1. OSコマンドインジェクション
悪い例(文字列連結で実行)
filename = params[:file]system("cat #{filename}") # 任意コマンドを混ぜられる
良い例(引数を分ける/検証する)
filename = params[:file].to_sraise "invalid" unless filename.match?(/\A[\w.\-]+\z/) # ホワイトリストsystem("cat", filename) # シェルを介さない
■ 2. SQLインジェクション
悪い例
name = params[:name]User.where("name = '#{name}'")
良い例(プレースホルダ)
name = params[:name]User.where("name = ?", name)# あるいはUser.where(name: name)
■ 3. XSS(クロスサイトスクリプティング)
悪い例
<%= params[:comment] %>
良い例(エスケープ)
<%= h(params[:comment]) %>
※Railsは通常自動エスケープだが、raw などを使うと危険
■ 4. パス・トラバーサル
悪い例
path = "/var/www/uploads/" + params[:file]File.read(path)
良い例(パス正規化+制限)
base = File.expand_path("/var/www/uploads")target = File.expand_path(File.join(base, params[:file].to_s))raise "invalid path" unless target.start_with?(base + "/")File.read(target)
■ 5. YAMLデシリアライズ
悪い例
YAML.load(params[:data]) # 任意オブジェクト生成の危険
良い例
YAML.safe_load(params[:data], permitted_classes: [Hash, Array, String, Integer])
■ 6. パスワード管理
悪い例
user.password = params[:password] # 平文保存はNG
良い例(ハッシュ化)
require 'bcrypt'user.password_digest = BCrypt::Password.create(params[:password])
■ 7. CSRF対策(Rails)
protect_from_forgery with: :exception
フォーム側:
<%= csrf_meta_tags %>
■ 8. 入力バリデーションの基本
def valid_email?(email) email.match?(/\A[^@\s]+@[^@\s]+\z/)end
※「ブラックリスト」よりホワイトリストが基本
■ まとめ(重要ポイント)
・外部入力は絶対に信用しない
・「連結」ではなく**安全なAPI(引数分離・プレースホルダ)**を使う
・エスケープと検証を分けて考える
・危険な機能(eval, system, YAML.loadなど)は慎重に扱う
この記事へのコメント