2016-12-31 10 views
16

これについては、いろいろなSOのスレッド、ガイドなどでお伝えしていますが、すべての回答は矛盾して矛盾しています。Rails 5 SQL Injection

多くの類似の方法があるようですが、多くの回答では別の方法を使用すると言われています。

  • sanitize
  • sanitize_conditions
  • sanitize_sql
  • sanitize_sql_array
  • sanitize_sql_for_assignment
  • sanitize_sql_for_conditions
  • sanitize_sql_hash
  • sanitize_sql_hash_for_assignment
  • sanitize_sql_hash_for_conditions
  • sanitize_sql_like

私は私が生のPostgresのクエリを実行することができます「生のクエリ」アダプタを書き込もうとしますが、私は危険なユーザー入力から来た私自身のパラメータを挿入することが可能です。

私は複雑な緯度/経度の計算、集計機能、複雑なサブクエリなど

これまでのところ、私が試してみました2つのアプローチやっているので、私はこれらのいくつかのインスタンスでARを使用することはできません

を方法1この方法については

sanitizeは、上記の最良の選択肢である場合、またはそれが例100%で動作する場合、私は

(私はPostgresのを使用しています)...知りません
class RawQuery 

    def exec(prepared, *params) 
    prepared = query.dup 
    params.flatten.each_with_index do |p, i| 
     prepared.gsub!("$#{i + 1}", ActiveRecord::Base.sanitize(p)) 
    end 
    ActiveRecord::Base.connection.exec_query(prepared) 
    end 

end 

些細な使用例(通常はそれが当然のこの単純ではないでしょうか、私はちょうどARを使用します):

RawQuery.new.exec('SELECT * FROM users WHERE name = $1', params[:name])

さらにそれがquotesanitize委譲しているようです。しかし、this SO postによれば、単引用符で物をラップするだけでは安全ではないので...私は考えていません。

方法2

私は、これは同じように安全であるかどうかわからないんだけど、実際のP​​Gを使用しているようだ(私は100%安全であると仮定している)機能を用意しました。唯一の問題は、レールがコンソールに表示されず、SQL実行時間(プロファイリングツールが破損する)が含まれないことです。

RawQuery.new.prepare('SELECT * FROM users WHERE name = $1', params[:name])


は別をより安全な一つの方法である:?同じように使用

class RawQuery 

    def prepare(query, *params) 
    name = "raw_query_#{SecureRandom.uuid.gsub('-', '')}" 
    connection = ActiveRecord::Base.connection.raw_connection 
    connection.prepare(name, query) 
    connection.exec_prepared(name, params) 
    end 

end 

両方とも100%安全ですか?

私のアプリは、常にRailsがSQLに対応しているものの外に広がっています。私が知っている私のすべてのプロジェクトにインクルードすることができます。

答えて

9

quoteを使用すると安全です。私はthe page you linked toの答えを読んで、私はquoteが安全でないと言っている人はいません。私は引用符を使用することについてのあなたの質問を参照してください。あなただけの文字列の前後に引用符を置く場合は、[はい、それは安全ではない、例えば:

q = "SELECT * FROM users where email = '#{params[:email]}'" 

しかしquoteを使用して(方法)で結構です。

q = "SELECT * FROM users where email = #{connection.quote(params[:email])}" 

あなたは、コンソールで遊ぶと試みることができますあなたの最高のそれを破壊するが、私はにあなたができるようになりますとは思わない:あなたが成功した場合

2.3.3 :003 > ActiveRecord::Base.connection.quote("f''oo")                    
=> "'f''''oo'" 

が、私は確信しているRailsのチームが(個人的に)知っていただきたいと思います!しかし、あなたが見ることができるように、quoteメソッドは最初と最後に引用符を付ける以上のことをします。また

、あなたが正式な引用を探していると言うことから、ソースコード自体のコメントは、ユーザの入力を引用することは、これらの機能の使用目的であることを示唆している:

https://github.com/rails/rails/blob/2471e6391dfe71cfbb8621bdf573729d961d3209/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb#L6-L13

# Quotes the column value to help prevent 
# {SQL injection attacks}[http://en.wikipedia.org/wiki/SQL_injection]. 
def quote(value) 

https://github.com/rails/rails/blob/0f1d0b1b5254e3678abaabbebb3362a100c10262/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb#L17-L20

# Quotes strings for use in SQL input. 
def quote_string(s) #:nodoc: 

(注:コメントにはquote_stringが表示されていますが、 。SE quote、データの種類を把握し、適切な何かをしようとしている)

ところで、ここでいくつかの選択肢があまりにも2014年に私からの回答で、あなたに似た質問です、そして:How to execute a raw update sql with dynamic binding in rails

+0

私は理解します。では、 'sanitize'と' sanitize_sql_for_conditions'の主な違いは何ですか?私が最初の質問に含めることを忘れていたもう1つの部分は、 'method sanitize_sql_for_conditions'の文書には、** WHERE **句の有効なSQLフラグメントにそれらをサニタイズすることです。 'sanitize'のドキュメントは次のように言っています:オブジェクトがSQL ** SELECT **ステートメントで使用される前にオブジェクトをサニタイズするのに使われました。それは状況依存であり、SQL文のどこでも使用できないメソッドなのでしょうか? (SELECT、WHERE、GROUP BYなどで)。または、場所に関係なく 'sanitize'を使用できますか? – Tallboy

+2

'sanitize_ *'メソッドはすべて保護されているように見えますから、あなたがそれらを使うつもりはないと思います。私はいつも 'quote'がこのようなことに使う主な公的方法であると理解してきました。実際、単純な 'sanitize'メソッドは単にあなたが言ったように' quote'を呼び出します。コードを見るだけで、他の 'sanitize_ *'メソッドは本当にRailsyのデータ構造( '{name:" foo "、email:" [email protected] "}')と 'quote' 。彼らはそれぞれの値に対して 'quote'を呼び出します。 '* for_conditions'と' * for_assignment'は主に '、'と 'と'を使っているようです。 –

+0

助けてくれてありがとう!素晴らしい答え。 – Tallboy