【发布时间】:2017-05-15 14:40:43
【问题描述】:
我已经在各种 SO 线程、指南等上阅读了一段时间...但所有答案都是相互矛盾的。
似乎有很多类似的方法,很多答案都说要使用不同的方法。
sanitizesanitize_conditionssanitize_sqlsanitize_sql_arraysanitize_sql_for_assignmentsanitize_sql_for_conditionssanitize_sql_hashsanitize_sql_hash_for_assignmentsanitize_sql_hash_for_conditionssanitize_sql_like
我正在尝试编写一个“原始查询”适配器,它允许我运行原始 Postgres 查询,但允许我插入来自危险用户输入的我自己的参数。
在这几个例子中我不能使用 AR,因为我正在执行复杂的纬度/经度计算、聚合函数、复杂的子查询等。
到目前为止,我已经尝试了两种方法:
方法一
对于这种方法,我不知道sanitize 是否是上述方法的最佳选择,或者它是否适用于 100% 的情况...(我只使用 Postgres)
class RawQuery
def exec(prepared, *params)
prepared = query.dup
params.flatten.each_with_index do |p, i|
prepared.gsub!("$#{i + 1}", ActiveRecord::Base.sanitize(p))
end
ActiveRecord::Base.connection.exec_query(prepared)
end
end
琐碎的用法示例(通常当然不会这么简单,或者我只会使用 AR):
RawQuery.new.exec('SELECT * FROM users WHERE name = $1', params[:name])
此外,sanitize 似乎代表quote。但是根据this SO post,它说简单地用单引号包裹东西是不安全的......所以我不知道。
方法二
我不确定这是否同样安全,但它似乎使用了一个实际的 PG 准备函数(我假设它是 100% 安全的)。唯一的问题是 rails 不会将其打印到控制台,也不会包含 SQL 执行时间(这会破坏我的分析工具)。
class RawQuery
def prepare(query, *params)
name = "raw_query_#{SecureRandom.uuid.gsub('-', '')}"
connection = ActiveRecord::Base.connection.raw_connection
connection.prepare(name, query)
connection.exec_prepared(name, params)
end
end
用同样的方法:
RawQuery.new.prepare('SELECT * FROM users WHERE name = $1', params[:name])
一种方法比另一种方法更安全吗?两者都是 100% 安全的吗?
我的应用程序总是远远超出 Rails 的 SQL 能力,我需要一个可以包含在我所有项目中的好库,我知道它是完全安全的。
【问题讨论】:
标签: ruby-on-rails ruby postgresql activerecord ruby-on-rails-5