Ответ 1
Попробуйте следующее:
connect = ActiveRecord::Base.connection();
connect.execute(ActiveRecord::Base.send(:sanitize_sql_array, "your string"))
Вы можете сохранить его в переменной и использовать для своих целей.
Есть ли способ дезинформировать 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
Edit:
Хорошо, мой клиент попросил сделать эту функцию (выберите по sql) в панели администратора, чтобы сделать сложный запрос (объединения, особые условия и т.д.). Поэтому я действительно хочу find_by_sql, что.
Второе редактирование:
Я хочу достичь этого "злого" кода SQL, который не будет выполнен.
В панели администратора вы можете ввести запрос → Update users set admin = true where id = 232
, и я хочу заблокировать любую команду UPDATE/DROP/ALTER SQL.
Просто хочу знать, что здесь вы можете ТОЛЬКО выполнять SELECT.
После некоторых попыток я заключаю sanitize_sql_array
, к сожалению, этого не делают.
Есть ли способ сделать это в Rails?
Извините за путаницу..
Попробуйте следующее:
connect = ActiveRecord::Base.connection();
connect.execute(ActiveRecord::Base.send(:sanitize_sql_array, "your string"))
Вы можете сохранить его в переменной и использовать для своих целей.
Я сделал небольшой фрагмент для этого, чтобы вы могли ввести инициализаторы.
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)
Немного более универсальный:
class ActiveRecord::Base
def self.escape_sql(clause, *rest)
self.send(:sanitize_sql_array, rest.empty? ? clause : ([clause] + rest))
end
end
Это позволяет вам называть его так же, как вы вводите предложение where без дополнительных скобок и используете либо массив-стиль? или интерполяции в стиле хэш.
User.find_by_sql(["SELECT * FROM users WHERE (name = ?)", params])
Источник: http://blog.endpoint.com/2012/10/dont-sleep-on-rails-3-sql-injection.html
Хотя этот пример для запроса 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 "Не позволяйте им сбивать вас" станет "Не позволяйте им сбивать вас".