Is ActiveRecord's “order” method vulnerable to SQL injection?

后端 未结 5 2198
我寻月下人不归
我寻月下人不归 2020-12-17 10:32

I know it\'s not safe to use interpolated strings when calling .where.

e.g. this:

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

相关标签:
5条回答
  • 2020-12-17 11:01

    Short answer is you need to sanitize your inputs.

    If the strings you are planning to interpolate come from an untrusted source (e.g. web browser) then you need to first map them to trusted values. You could do this via a hash:

    # 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)
    
    0 讨论(0)
  • 2020-12-17 11:14

    Let's try this!

    # 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
    
    0 讨论(0)
  • 2020-12-17 11:17

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

    should be written as

    order = sanitize_sql_array(['%s, %s', some_value_1, some_value_2])
    Client.order(order)
    
    0 讨论(0)
  • 2020-12-17 11:18

    Yes, ActiveRecord's “order” method is vulnerable to SQL injection.

    No, it is not safe to use interpolated strings when calling .order.

    The above answers to my question have been confirmed by Aaron Patterson, who pointed me to http://rails-sqli.org/#order . From that page:

    Taking advantage of SQL injection in ORDER BY clauses is tricky, but a CASE statement can be used to test other fields, switching the sort column for true or false. While it can take many queries, an attacker can determine the value of the field.

    Therefore it's important to manually check anything going to order is safe; perhaps by using methods similar to @dmcnally's suggestions.

    Thanks all.

    0 讨论(0)
  • 2020-12-17 11:19

    @Mike explanation is correct. @dmcnally workaround would work. I'm following in a slightly different path mentioned in [Railscast][1] http://railscasts.com/episodes/228-sortable-table-columns

    In a nutshell, if you can construct a private method in the controller, in order to sanitize the user input:

    1. Order by name of one your table columns:

          private 
      
          def sort_column
             Client.column_names.include?(params[:sort]) ? params[:sort] : "first_name"
          end
      
    2. Order by other criteria, then use the whitelist construct such as below:

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

    And your controller method should then look like this:

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

    Just anther way to Rome. Hope this help.

    0 讨论(0)
提交回复
热议问题