mysql - 如何保护 Rails find_by_SQL 语句免受 SQL 注入(inject)?

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

感谢您对此的帮助!我正在开发一个旧版 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/

相关文章:

ruby-on-rails - Prawn gem 支持阿拉伯语吗?

php - 如何在php mysql提交表单中停止自动乘法

php - 如何防止 PHP 中的 SQL 注入(inject)?

ruby-on-rails - (postgreSQL 错误)致命:角色 "demo"不存在(PG::错误)

ruby-on-rails - Rails 4 CSV 导入并将值设置为键值

php - PHP 中 $mysqli->real_escape_string 的正确用法

mysql - Load infile 语句抛出错误

mysql - 在 MySQL 查询中计算百分比

php - 在 php 中获取错误的 IP 地址

mysql - APIMan 与 Tomcat 和 MySQL