如何在Ruby on Rails网站上使用此搜索功能来避免SQL注入?

时间:2013-01-17 23:09:15

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

提前感谢您提供的任何帮助!我已经回顾了Stack Overflow上的类似文章和这些文章:

但是,我对MySQL很新,并且正在使用由另一个开发团队创建的Ruby on Rails网站。我只是在为我的情况拼凑不同的文章时遇到了麻烦。

我知道我的代码中存在SQL注入漏洞,我需要使用参数。我只是不确定如何使用我的代码。我在下面列出了部分内容:

在我的search.html.erb中,SELECT语句显示为:

@office_matches = Masterlocation.paginate_by_sql("select * from mylocations where #      {search_string} order by nickname asc",  :page => params[:page], :per_page => 20)

然后,在search_controller.rb中,它显示为:

def results
@search_string = ""

@first_term = 'y'
      params[:search_terms_new] = "something in here so loop works"
    if params[:search_terms_new] != ""

# debugger

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

if params[:search][:state] != ""
  @search_string << "and state = '#{params[:search][:state]}' "
  if @first_term == 'y'
    @search_string = @search_string.gsub('and ', " ")
    @first_term = 'n'
  end
end

我应该如何更改此代码以防止SQL注入攻击?

1 个答案:

答案 0 :(得分:2)

我认为你应该重构你使用模型范围的方法。

首先将基于范围的函数或作用域放在模型中。这是我的一个模型,我已经排除了一些与此示例无关的位。下面你会看到我有两个功能;一个按帐号分组搜索,另一个按帐号搜索。

account_grouping函数与下拉框一起使用,其中下拉列表中的第一项是“all”,而帐户搜索是文本搜索字段。

class CostTypeAllocation < ActiveRecord::Base

  attr_accessible :fiscal_year_id, :fiscal_period_id, :cost_centre_id, :account_grouping, :account_code, :account, :fixed_percentage,
    :marginal_percentage, :incremental_percentage,  :non_applicable_percentage

  scope :in_sort_order, order("fiscal_year_id DESC, fiscal_period_id DESC, account_code")

  # Allow for searching by Account Grouping
  def self.search_account_grouping(account_grouping)
    if account_grouping
      case account_grouping
      when 'all'
        scoped
      else
        where("account_grouping = ?", account_grouping)
      end
    else
      scoped
    end

  end

  # Search the text of the account
  def self.search_account(account)
    if account
      where("account LIKE ?", "%#{account.downcase}%")
    else
      scoped
    end
  end
end

现在我的控制器中的功能处理搜索。

class Admin::CostTypeAllocationsController < ApplicationController
  before_filter :authenticate_user!
  def index
    @search_account_grouping = params[:search_account_grouping] || 'all'
    @search_account = params[:search_account]
    @cost_type_allocations = CostTypeAllocation.search_account_grouping(@search_account_grouping).search_account(@search_account).in_sort_order.paginate(:page => params[:page], :per_page => 10)

  end
end

因此控制器或参数中没有SQL。所有内容都封装在模型中。分页由will_paginate gem处理。


回复你的评论 代码的位置并不重要,但最好将所有数据访问保留在模型层中。

您的主要问题是在字符串中使用#{params [:city]}。用户在参数中输入的任何内容都将放入SQL中,因此允许SQL注入攻击。 where('city like?',“%#{params [:city]}%”)是安全的,因为rails会在构造where子句之前过滤出param中的任何SQL。

设置一个范围,用于指明城市和州的状况,就像我为帐户设置的那样;一旦你有了那些,你就可以去model.cityscope(params [:city])。statescope(params [:state])和rails将根据需要将它们链接在一起。

我想你需要将范围放在任何具有城市和州的模型中。

请参阅http://guides.rubyonrails.org/security.html

上的安全指南

继续发表评论后,我认为这就是您可能正在寻找的内容。

在你的模特中

def self.search_city(city)
    if city
        where ("city LIKE ?", "%#{city}%")
    else
        scoped
    end
end

def self.search_state(state)
    if state
        where ("state LIKE ?", "%#{state}%")
    else
        scoped
    end
end

在您的控制器中

@collection_for_view = Model.search_city(params[:city]).search_state(params[:state])

在每种情况下,如果参数已设置,搜索功能将返回where过滤器,如果为空,则返回所有记录。