はエスケープ処理をしない(できない) 🔑 安全かどうかを見極めるポイント irb(main):001> User.where("name = 'joe' AND age > 20") User Load (1.2ms) SELECT `users`.* FROM `users` WHERE (name = 'joe' AND age > 20) /* loading for pp */ LIMIT 11 mysql irb(main):001> User.where("name = '' OR true") User Load (3.3ms) SELECT "users".* FROM "users" WHERE (name = '' OR true) /* loading for pp */ LIMIT $1 [["LIMIT", 11]] postgresql
• 例外により SQL インジェクション攻撃は成立しない irb(main):001> User.order("age desc; SELECT * FROM users;--") (irb):1:in `<main>': Dangerous query method (method whose arguments are used as raw SQL) called with non-attribute argument(s): "age desc; SELECT * FROM users;--".This method should not be called with user-provided values, such as request parameters or model attributes. Known-safe values can be passed by wrapping them in Arel.sql(). (ActiveRecord::UnknownAttributeReference) postgresql
- created_at desc") (irb):1:in `<main>': Dangerous query method (method whose arguments are used as raw SQL) called with non-attribute argument(s): "updated_at - created_at desc".This method should not be called with user-provided values, such as request parameters or model attributes. Known-safe values can be passed by wrapping them in Arel.sql(). (ActiveRecord::UnknownAttributeReference) postgresql irb(main):002> User.order(Arel.sql("updated_at - created_at desc")) User Load (4.0ms) SELECT "users".* FROM "users" /* loading for pp */ ORDER BY updated_at - created_at desc LIMIT $1 [["LIMIT", 11]] postgresql
this primary key. ◦ String - Finds the record with a primary key corresponding to this string (such as '5'). ◦ Array - Finds the record that matches these where-style conditions. ◦ Hash - Finds the record that matches these where-style conditions. ◦ false - Returns always false. ◦ No args - Returns false if the relation is empty, true otherwise. • Array の場合は SQL フラグメントを受け付ける ◦ e.g.) Person.exists?(['name LIKE ?', "%#{query}%"]) • 一方 params[:id] はクエリストリング次第で Array の値もとる ◦ ?id[]=1%3D1 → Parameters: {"id"=>["1=1"]} ☠ User.exists?(params[:id])
User.exists?(params[:id]) end end app/controllers/users_controller.rb Started GET "/users/index?id[]=1%3D1" for ::1 at 2024-10-15 09:03:07 +0900 Processing by UsersController#index as HTML Parameters: {"id"=>["1=1"]} User Exists? (1.5ms) SELECT 1 AS one FROM "users" WHERE (1=1) LIMIT $1 [["LIMIT", 1]] : Completed 200 OK in 14ms (Views: 11.0ms | ActiveRecord: 1.4ms | Allocations: 1892) log/development.log
books b ON b.type = '#{type}'") • sanitize_sql_array メソッドを使う ◦ e.g.) User.joins(User.sanitize_sql_array(["INNER JOIN books b ON b.type = ?", type])) • sanitize_sql_like など状況別に利用できる API が用意されている ◦ API リファレンスを確認しておくと良い