Rails 3では、sanitize_sql_array
を使用して、生のSQLクエリが必要な場合に備えて、生のSQLをサニタイズできます。しかし、これはRails 4で削除されたか、それほど削除されていないようですが、ActiveRecord :: Sanitizationに移動しました。しかし、今はsanitize_sql_array
を呼び出す方法がわからないので、Rails 4で生のSQLをサニタイズする最良の方法は何ですか?
ここでは、Railのモデルを使用せずに、完全な生のSQLクエリについて話していることを明確にしたいと思います。私はこれがベストプラクティスではないことを認識しています。これは、RailsのNice ActiveRecordインターフェースでは表せないため、この特定のクエリに対して実行しなければならないことです(私を信じて、試してみました)。
これはサンプルコールで、クエリが実際にどのように表示されるかよりも明らかに単純です。
query = "SELECT * FROM users
LEFT OUTER JOIN posts ON users.id=posts.user_id
AND posts.topic_id = '#{topic.id}'"
# ^- Obviously bad and very vulnerable, this is what we're trying to fix
ActiveRecord::Base.connection.select_all(query)
生のSQLを書く必要がある場合は、 quote
を使用してサニタイズできます。
conn = ActiveRecord::Base.connection
name = conn.quote("John O'Neil")
title = conn.quote(nil)
query = "INSERT INTO users (name,title) VALUES (#{name}, #{title})"
conn.execute(query)
Active Record docs から、SQLクエリをサニタイズする最良の方法は、avoidを使用して、独自の条件を純粋な文字列として構築することですつまり、次のように、クエリにパラメータを直接挿入します。
User.find_by("user_name = '#{user_name}' AND password = '#{password}'")
代わりに、配列またはハッシュ条件を使用します。
配列条件:
Client.where("orders_count = ? AND locked = ?", params[:orders], false)
ハッシュ条件:
Client.where(is_active: true)
明確な例:
class User < ActiveRecord::Base
# UNSAFE - susceptible to SQL-injection attacks
def self.authenticate_unsafely(user_name, password)
where("user_name = '#{user_name}' AND password = '#{password}'").first
end
# SAFE
def self.authenticate_safely(user_name, password)
where("user_name = ? AND password = ?", user_name, password).first
end
# SAFE
def self.authenticate_safely_simply(user_name, password)
where(user_name: user_name, password: password).first
end
end
ここにいくつかの参照があります:
Quoteメソッドとその他のActiveRecord::Base
サニタイズメソッドは廃止され、パブリックAPIの一部にはなりませんでした。
https://github.com/Rails/rails/issues/28947
公式の消毒方法は
http://api.rubyonrails.org/classes/ActiveRecord/Sanitization/ClassMethods.html