16

有没有办法在 rails 方法中清理 sql find_by_sql

我试过这个解决方案: Ruby on Rails: How to sanitize a string for SQL when not using 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 代码。

在管理面板中,您可以键入 query ->Update users set admin = true where id = 232我想阻止任何 UPDATE / DROP / ALTER SQL 命令。只想知道,在这里你只能执行 SELECT。

经过一些尝试,我很sanitize_sql_array遗憾地得出结论,不要那样做。

有没有办法在 Rails 中做到这一点?

对困惑感到抱歉..

4

6 回答 6

14

尝试这个:

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

您可以将其保存在变量中并用于您的目的。

于 2011-08-22T09:50:08.177 回答
10

我为此制作了一个小片段,您可以将其放入初始化程序中。

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)
于 2011-08-22T10:05:57.770 回答
8

稍微通用一点:

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

这个让您可以像输入 where 子句一样调用它,无需额外的括号,并使用任一数组样式 ? 或散列式插值。

于 2011-10-20T19:05:08.223 回答
7
User.find_by_sql(["SELECT * FROM users WHERE (name = ?)", params])

来源:http ://blog.endpoint.com/2012/10/dont-sleep-on-rails-3-sql-injection.html

于 2016-10-19T02:50:38.197 回答
1

虽然这个示例是针对 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

这是ActiveRecord::Base 中对 sanitize_sql_array 方法的引用,它通过转义字符串中的单引号来生成正确的查询字符串。例如,妙语“不要让他们让你失望”将变成“不要让他们让你失望”。

于 2011-11-04T10:09:07.993 回答
0

我更喜欢用关键参数来做。在您的情况下,它可能如下所示:

  Model.find_by_sql(["UPDATE user set active = :active where id = :id", active: 0, id: 1])

请注意,您只将一个参数传递给:find_by_sql方法 - 它是一个数组,其中包含两个元素:字符串查询和带参数的哈希(因为它是我们最喜欢的 Ruby,您可以省略大括号)。

于 2020-12-02T03:47:34.437 回答