如何从SQL注入中保护这个Rails find_by_SQL语句?

时间:2014-01-04 22:39:20

标签: mysql ruby-on-rails sql-injection ruby-on-rails-2

感谢您对此的帮助!我正在研究一个传统的Rails应用程序,我已经检查了一些来源但是无法让它们适合我的情况。在Rails 2.3中,我有一个搜索表单(index.html.erb)和一个控制器(search.rb)。控制器使用搜索字段构建一个字符串,该字符串保存在变量@search_string中。

    @search_string = ""

要显示搜索结果,控制器使用:

    @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(预期参数hash)。仅供参考,@ search_string使用如下表单字段构建:

FORM

    <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

控制器

    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"=>""}}

1 个答案:

答案 0 :(得分:0)

简短的回答是:你真的不能很快这样做。

我建议更新搜索字符串构建器,而不是只创建一个字符串,以构建数组样式的查找器集,例如:["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)