感谢您对此的帮助!我正在开发一个旧版 Rails 应用程序,并且检查了一些来源,但无法使它们适合我的情况。在 Rails 2.3 中,我有一个搜索表单 (index.html.erb) 和一个 Controller (search.rb)。 Controller 使用搜索字段构建一个字符串,该字符串保存在变量@search_string中。
@search_string = ""
为了显示搜索结果, Controller 使用:
@location_matches = Location.paginate_by_sql("select * from locations where #{@search_string} order by nickname asc", :page => params[:page], :per_page => 20)
对我来说,清理上述内容的最简单方法是什么?我试过了
@location_matches = Location.paginate_by_sql('SELECT * FROM locations WHERE #{@search_string} = ?', @search_string)
这会引发错误 ArgumentError(需要参数哈希值)。仅供引用,@search_string 是使用如下表单字段构建的:
表格
<label for="city">City</label>
<input id="city" name="city" size="30" type="text" value="" />
Controller
if params[:city] != ""
@search_string << "and city like '%#{params[:city]}%' "
if @first_term == 'y'
@search_string = @search_string.gsub('and ', " ")
@first_term = 'n'
end
end
我很确定各个字段没有正确参数化,但我并没有遍历每个字段并尝试修复它,而是通过调整 paginate_by_sql 语句来寻找更快的解决方案(我是 Rails 新手)我只是想快速修复,因为整个应用程序最终需要升级。)
编辑
我按照 Rails, how to sanitize SQL in find_by_sql 中的步骤操作并添加了一个初始化程序。我还将我的声明更改为以下内容。但是,当我运行搜索时,我没有得到任何结果。我还必须删除升序条件,因为它引发了错误。任何想法都非常受欢迎!
初始化器
class ActiveRecord::Base
def self.escape_sql(clause, *rest)
self.send(:sanitize_sql_array, rest.empty? ? clause : ([clause] + rest))
end
end
Controller
query = Location.escape_sql(["SELECT * from locations WHERE #{@search_string} = ?", params[:@search_string]])
@location_matches = Location.paginate_by_sql(query, :page => params[:page], :per_page => 20)
日志(看起来与返回结果的代码相同)
Parameters: {"city"=>"New York", "commit"=>"Search", "search"=>{"size_category"=>"", "state"=>""}}
最佳答案
简短的回答是:你真的无法很快做到这一点。
我建议更新搜索字符串构建器,而不是仅创建单个字符串,而是构建数组样式的查找器集,例如:["field = ?", param]
例如:
search_string = ""
search_vals = []
if params[:city].present?
search_string << "and city like ? "
search_vals << "%#{params[:city]}%"
end
if params[:whatever].present?
search_string << "and whatever like ? "
search_vals << "%#{params[:whatever]}%"
end
然后当你想要进行最终搜索时,你可以这样使用它:
search_string = "SELECT * from locations WHERE #{search_string}"
# turns it into the array-with question-mark syntax
search_query = [search_string] + search_vals
# if paginate_by_sql takes array, you can use it straight up here:
@location_matches = Location.paginate_by_sql(search_query, :page => params[:page], :per_page => 20)
# otherwise use your "escape_sql" variant first
@location_matches = Location.paginate_by_sql(Location.escape_sql(search_query), :page => params[:page], :per_page => 20)
关于mysql - 如何保护 Rails find_by_SQL 语句免受 SQL 注入(inject)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20927625/