2013-07-25 31 views
11

Tôi biết không an toàn khi sử dụng các chuỗi nội suy khi gọi .where.Phương thức "order" của ActiveRecord có dễ bị tấn công SQL injection không?

ví dụ: này:

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

nên được viết lại như sau:

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

Có an toàn để sử dụng chuỗi nội suy khi gọi .order? Nếu không, làm thế nào sau đây nên được viết lại?

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

Trả lời

15

Vâng, ActiveRecord của “trật tự” phương pháp dễ bị SQL injection.

Không, nó là không an toàn để sử dụng chuỗi nội suy khi gọi .order.

Câu trả lời ở trên cho câu hỏi của tôi đã được xác nhận bởi Aaron Patterson, người đã chỉ cho tôi http://rails-sqli.org/#order. Từ trang đó:

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.

Do đó, việc kiểm tra thủ công mọi thứ đến order là an toàn; có lẽ bằng cách sử dụng các phương pháp tương tự như đề xuất của @ dmcnally.

Cảm ơn tất cả.

+0

Hey @Mike Tôi hỏi một câu hỏi về điều này bởi vì tôi không hiểu nó hoạt động như thế nào. Bạn có thể trợ giúp: http://stackoverflow.com/questions/28630381/explain-how-order-clause-can-be-exploited-in-rails –

-2

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

nên được viết như

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

Điều đó sẽ không được an toàn Mike, tạo ra một bảng giả bạn không nhớ mất và làm như sau: Client.order ('id asc; thả bảng giả;') Bạn có thể ngạc nhiên – dmcnally

+1

Bạn nói đúng, Dave. 'Model..send (: sanitize_sql_array, ['mike% s', '; DROP BẢNG X']) =>" mike; DROP TABLE X "'. Vậy làm thế nào để chúng ta làm cho nó an toàn như chúng ta sẽ làm với 'where'? – Mike

+0

@dmcnally: "ActiveRecord :: StatementInvalid: PG :: Cú phápError: ERROR: không thể chèn nhiều lệnh vào câu lệnh đã chuẩn bị" – Dorian

5

Câu trả lời ngắn là bạn cần phải khử trùng đầu vào của bạn.

Nếu chuỗi bạn dự định nội suy đến từ nguồn không đáng tin cậy (ví dụ: trình duyệt web) thì trước tiên bạn cần ánh xạ chúng tới các giá trị đáng tin cậy. Bạn có thể làm điều này thông qua một băm:

# 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

Đó là hữu ích, cảm ơn. Truy vấn thứ tự thực tế của tôi phức tạp hơn câu hỏi và cần có đầu vào tùy ý của người dùng.Lý tưởng nhất, tôi muốn sử dụng một cú pháp mảng như tôi sẽ với 'where'. Tóm lại, bạn có nói rằng tôi phải tự mình làm việc không? :) – Mike

0

Hãy thử điều này!

# 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 
Các vấn đề liên quan