2013-07-25 16 views
11

.whereを呼び出すときに、補間された文字列を使用することは安全ではないことが分かります。ActiveRecordの「注文」メソッドはSQLインジェクションに対して脆弱ですか?

これは:

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

のように書き換えることが必要です。

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

.orderを呼び出すときには、補間文字列を使用しても安全ですか?そうでない場合は、どのように書き直すべきですか?

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

答えて

15

:あなたはハッシュを経由してこれを行うことができます。

いいえ、.orderを呼び出すときに、補間文字列を使用しては安全ではありません。

私の質問に対する上記の回答は、Aaron Pattersonによって確認されました。私はhttp://rails-sqli.org/#orderを指摘しました。そのページから:

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.

したがって、それは手動で安全であるorderに行く何かを確認することが重要です。おそらく@ dmcnallyの提案に似た方法を使用します。

ありがとうございます。

+0

こんにちは@私はそれがどのように動作するか理解できなかったため、これについての質問をしました。助けてください:http://stackoverflow.com/questions/28630381/explain-how-order-clause-can-be-exploited-in-rails –

-2

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

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

驚いた – dmcnally

+1

あなたはそうだ、Dave。 Model.send(:sanitize_sql_array、['mike%s'、 '; DROP TABLE X'])=> "mike; DROP TABLE X"。だから、どこで 'どこで'と同じように安全にするのでしょうか? – Mike

+0

@dmcnally: "ActiveRecord :: StatementInvalid:PG :: SyntaxError:ERROR:プリペアドステートメントに複数のコマンドを挿入できません" – Dorian

5

短い答えはあなたの入力をサニタイズする必要があるように記述する必要があります。

補間しようとしている文字列が信頼できないソース(Webブラウザなど)からのものである場合は、まずその値を信頼できる値にマップする必要があります。はい、ActiveRecordのの「注文」方法 SQLインジェクションの脆弱性である

# 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

これは役に立ちます、ありがとう。実際の注文クエリは質問よりも複雑で、任意のユーザー入力が必要です。理想的には、 'where'と同じような配列構文を使いたいと思っています。要約すると、自分で仕事をしなければならないと言っていますか? :) – Mike

0

これを試してみましょう!あなたがかもしれない Client.order(「;テーブルのダミーをドロップのid ASC」):、安全なマイクもあなたが失うことを気にしないダミーのテーブルを作成し、次の操作を行うことはありません

# 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 
関連する問題