Rails 4 在 "Where" 方法中安全使用变量

Rails 4 safely using variables in "Where" method

我自己搜索了一个 Rails 4 应用程序。现在我需要为用户提供不同的列来进行搜索。我在视图的搜索表单中创建了一个下拉菜单,如下所示:

<%= form_tag manage_accounts_administrator_path, :method => 'get', :id => "search-form" do %>
      <%= text_field_tag :search, params[:search], placeholder: 'Search Accounts' %>
      <%= select_tag("search_criteria", options_for_select([['by account number', '1'],['by customer id', '2'],['by customer name (ex: Jane Doe)', '3']])) %>
      <%= submit_tag "Search", :name => nil %>
<% end %>

然后在相应的控制器方法中,我这样做:

  def manage_accounts
    # criteria from the "Search by" select menu
    if params[:search]
        case (params[:search_criteria])
        when 1
          @criteria = id
        when 2
          @criteria = customer_id
        when 3 
          @criteria = customer.firstname + ' ' + customer.lastname
        end

        @accounts = Account.where("#{@criteria} LIKE ?", "%#{params[:search]}%").page(params[:page]).per(15)
        @table_heading = "Account Search Results"
    else
        @accounts = Account.order('id').page(params[:page]).per(15)
        @table_heading = "Listing All Accounts"
    end

    respond_to do |format|
      format.js
      format.html {render 'manage_accounts'}
    end
  end

上面 case 块中 @criteria 变量的三个可能值表示 "Account" 模型的字段。如您所见,我期望发生的是使用 "where" 方法进行的查询。此语法错误,我收到错误消息:

ActiveRecord::StatementInvalid in Administrators#manage_accounts Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'LIKE '%722586388%')' at line 1: SELECT COUNT(*) FROM accounts WHERE ( LIKE '%722586388%')

显然我做错了。 如何像插入搜索参数那样插入@criteria 变量?错误告诉我的是变量被完全转义。我已经尝试(猜测)了几十种不同的标点符号组合,但都无济于事。我觉得如果我的语法正确的话这会起作用。

此外,我了解到这是一种不好的做法,因为它会使应用容易受到 SQL 注入攻击。 那么,我应该如何以安全的方式编写此语句?

谢谢

rails 4.1.8 MySQL2 gem 我是菜鸟

您忘记用引号将您的变量括起来。当执行到行时

@accounts = Account.where("#{@criteria} LIKE ?", "%#{params[:search]}%").page(params[:page]).per(15)

@criteria 仍将是 nil。因此,activerecord 生成的 sql 将是 SELECT COUNT(*) FROM accounts WHERE ( LIKE '%722586388%') 而不是 SELECT COUNT(*) FROM accounts WHERE (id LIKE '%722586388%'),例如

所以在你的情况下,你将不得不这样做:

if params[:search]
    case (params[:search_criteria])
    when 1
      @criteria = 'id'
    when 2
      @criteria = 'customer_id'
    when 3 
      @criteria = 'customer.firstname'
    end
if params[:search]
    case (params[:search_criteria])
    when 1
      @criteria = "id"
    when 2
      #assuming you have a customer_id column in your accounts table
      @criteria = "customer_id"
    when 3 
      #assuming you have a customer_name column in your accounts table
      @criteria = "customer_name"
    end