ActiveRecord的“order”方法是否容易受到SQL注入攻击?

时间:2013-07-25 13:47:17

标签: sql ruby-on-rails-4

我知道在调用.where时使用插值字符串是不安全的。

e.g。这样:

Client.where("orders_count = #{params[:orders]}")

应改写为:

Client.where("orders_count = ?", params[:orders])

调用.order时使用插值字符串是否安全?如果没有,应该如何重写以下内容?

Client.order("#{some_value_1}, #{some_value_2}")

5 个答案:

答案 0 :(得分:16)

是的,ActiveRecord的“订单”方法 容易受到SQL注入攻击。

不,在调用.order时使用插值字符串 是安全的。

我的问题的上述答案已由Aaron Patterson确认,他指出http://rails-sqli.org/#order。从该页面:

  

在ORDER BY子句中利用SQL注入是棘手的,但是a   CASE语句可用于测试其他字段,切换排序   列为true或false。虽然它可能需要许多查询,但攻击者   可以确定该字段的值。

因此,手动检查前往order的任何内容是安全的非常重要;也许通过使用类似于@dmcnally建议的方法。

谢谢大家。

答案 1 :(得分:9)

简短的回答是你需要消毒你的输入。

如果您计划插入的字符串来自不受信任的来源(例如Web浏览器),那么您需要先将它们映射到受信任的值。你可以通过哈希来做到这一点:

# Mappings from known values to SQL
order_mappings = {
  'first_name_asc'  => 'first_name ASC',
  'first_name_desc' => 'first_name DESC',
  'last_name_asc'   => 'last_name ASC',
  'last_name_desc'  => 'last_name DESC',
}

# Ordering options passed in as an array from some source:
order_options = ['last_name_asc', 'first_name_asc']

# Map them to the correct SQL:
order = order_options.map{|o| order_mappings[o] }.compact.join(', ')
Client.order(order)

答案 2 :(得分:1)

@Mike的解释是正确的。 @dmcnally解决方法将起作用。我遵循的是[Railscast] [1] http://railscasts.com/episodes/228-sortable-table-columns

中提到的略有不同的路径

简而言之,如果您可以在控制器中构造一个私有方法,以便清理用户输入:

  1. 按表列之一的名称排序:

        private 
    
        def sort_column
           Client.column_names.include?(params[:sort]) ? params[:sort] : "first_name"
        end
    
  2. 按其他条件排序,然后使用以下白名单结构:

    def sort_direction
        %w[asc desc].include?(params[:direction]) ? params[:direction] : "asc"
    end
    

然后您的控制器方法应如下所示:

    Client.all.order(sort_column + " " + sort_direction)

前往罗马的另一条路。希望对您有所帮助。

答案 3 :(得分:0)

我们试试吧!

# app/models/concern/ext_active_record.rb
module ExtActiveRecord
    extend ActiveSupport::Concern

    included do
        scope :sortable, -> (params) do
            return unless params[:sort_by] && params[:sort_dir]
            reorder("#{params[:sort_by]}" => "#{params[:sort_dir]}")
        end
    end
end

# app/models/user.rb
class User < ActiveRecord::Base
    include ExtActiveRecord
    # ....
end

# app/controllers/user_controller.rb
class UserController < ApplicationController
    def index
        @users = User.sortable(params).page(params[:page]).per(params[:per])
    end
end

答案 4 :(得分:-2)

Client.order("#{some_value_1}, #{some_value_2}")

应该写成

order = sanitize_sql_array(['%s, %s', some_value_1, some_value_2])
Client.order(order)