はじめに
こんにちは。アメリカ在住で独学エンジニアを目指している Taira です。
Rails の order
メソッドは便利ですが、使い方を誤ると SQLインジェクション の原因になります。特に User.order(params[:sort])
のようにユーザー入力をそのまま渡すのは危険です。この記事では「なぜ危険なのか」「どう対策すべきか」を簡潔に解説します。
なぜ危険?
User.order(params[:sort])
order
は引数をそのまま SQL の ORDER BY
に展開します。ここにはプレースホルダが効かないため、Rails は自動でエスケープしてくれません。
もし攻撃者が次のような入力をしたら:
params[:sort] = "name; DROP TABLE users"
生成されるSQLは:
SELECT * FROM users ORDER BY name; DROP TABLE users;
➡️ DBによっては複文が実行され、テーブル削除などの被害につながります。
つまり、order
はユーザー入力をそのまま渡すと SQLインジェクションのリスク があります。
安全な書き方(ホワイトリスト)
許可するカラムと方向を明示的に制御します。
SORT_COLUMNS = {
"name" => "users.name",
"created" => "users.created_at"
}.freeze
def index
key = SORT_COLUMNS[params[:sort]] || "users.id"
dir = %w[asc desc].include?(params[:direction]) ? params[:direction] : "asc"
@users = User.order(Arel.sql("#{key} #{dir}"))
end
まとめ
-
order(params[:sort])
はSQLインジェクションの温床。 -
order
は列名や方向をそのままSQLに埋め込むため、Railsは自動で守ってくれない。 - ホワイトリスト化+asc/desc限定 が必須。