web-dev-qa-db-ja.com

生のSQLをRails 4でサニタイズする方法

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)
16
Colton Voege

生の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)
14
gabrielhilal

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

ここにいくつかの参照があります:

1
NickGnd

Quoteメソッドとその他のActiveRecord::Baseサニタイズメソッドは廃止され、パブリックAPIの一部にはなりませんでした。

https://github.com/Rails/rails/issues/28947

公式の消毒方法は

http://api.rubyonrails.org/classes/ActiveRecord/Sanitization/ClassMethods.html

1
lbaeyens