Rails, как санировать SQL в find_by_sql - PullRequest
16 голосов
/ 22 августа 2011

Есть ли способ очистки sql в методе rails find_by_sql?

Я пробовал это решение: Ruby on Rails: как очистить строку для SQL, когда не используется find?

Но происходит сбой при

Model.execute_sql("Update users set active = 0 where id = 2")

Выдает ошибку, но выполняется SQL-код, и у пользователя с ID 2 теперь отключена учетная запись.

Простойfind_by_sql также не работает:

Model.find_by_sql("UPDATE user set active = 0 where id = 1")
# => code executed, user with id 1 have now ban

Редактировать:

Ну, мой клиент попросил сделать эту функцию (выбрать по sql) в панели администратора, чтобы сделать некоторыесложный запрос (соединения, особые условия и т. д.).Поэтому я действительно хочу найти find_by_sql.

Второе редактирование:

Я хочу добиться того, чтобы «злой» код SQL не выполнялся.

В административной панели вы можете ввести запрос -> Update users set admin = true where id = 232, и я хочу заблокировать любую команду SQL UPDATE / DROP / ALTER.Просто хочу знать, что здесь вы можете ТОЛЬКО выполнить SELECT.

После некоторых попыток я заключаю, что sanitize_sql_array, к сожалению, не делайте этого.

Есть ли способ сделать это в Rails??

Извините за путаницу ..

Ответы [ 5 ]

13 голосов
/ 22 августа 2011

Попробуйте это:

connect = ActiveRecord::Base.connection();
connect.execute(ActiveRecord::Base.send(:sanitize_sql_array, "your string"))

Вы можете сохранить его в переменной и использовать для своих целей.

10 голосов
/ 22 августа 2011

Я сделал для этого небольшой фрагмент, который вы можете вставить в инициализаторы.

class ActiveRecord::Base  
  def self.escape_sql(array)
    self.send(:sanitize_sql_array, array)
  end
end

Прямо сейчас вы можете избежать запроса с помощью этого:

query = User.escape_sql(["Update users set active = ? where id = ?", true, params[:id]])

И вы можете вызватьзапросить любым удобным вам способом:

users = User.find_by_sql(query)
8 голосов
/ 20 октября 2011

Чуть более общего назначения:

class ActiveRecord::Base  
  def self.escape_sql(clause, *rest)
    self.send(:sanitize_sql_array, rest.empty? ? clause : ([clause] + rest))
  end
end

Этот позволяет вам вызывать его так же, как если бы вы вводили предложение where, без дополнительных скобок и используя любой стиль массива?или интерполяции в стиле хэша.

4 голосов
/ 19 октября 2016
User.find_by_sql(["SELECT * FROM users WHERE (name = ?)", params])

Источник: http://blog.endpoint.com/2012/10/dont-sleep-on-rails-3-sql-injection.html

1 голос
/ 04 ноября 2011

Хотя этот пример для запроса INSERT, можно использовать аналогичный подход для запросов UPDATE. Массовая вставка необработанного SQL:

users_places = []
users_values = []
timestamp = Time.now.strftime('%Y-%m-%d %H:%M:%S')
params[:users].each do |user|
    users_places << "(?,?,?,?)" # Append to array
    users_values << user[:name] << user[:punch_line] << timestamp << timestamp
end

bulk_insert_users_sql_arr = ["INSERT INTO users (name, punch_line, created_at, updated_at) VALUES #{users_places.join(", ")}"] + users_values
begin
    sql = ActiveRecord::Base.send(:sanitize_sql_array, bulk_insert_users_sql_arr)
    ActiveRecord::Base.connection.execute(sql)
rescue
    "something went wrong with the bulk insert sql query"
end

Вот ссылка на метод sanitize_sql_array в ActiveRecord :: Base , он генерирует правильную строку запроса, экранируя одинарные кавычки в строках. Например, punch_line «Не позволяйте им вас унизить» станет «Не позволяйте им вас унизить».

...