これについては、さまざまなSOスレッド、ガイドなどでしばらく読んでいますが、すべての答えは矛盾しており、矛盾しています。
似たような方法はたくさんあるようですが、答えの多くは別の方法を使うと言っています。
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クエリを実行できる「生のクエリ」アダプタを作成しようとしていますが、危険なユーザー入力から取得した独自のパラメータを挿入できます。
複雑なlat/long計算、集計関数、複雑なサブクエリなどを実行しているため、これらのいくつかのインスタンスではARを使用できません。
これまでに2つのアプローチを試しました。
方法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])
さらに、sanitize
は quote
に委任しているようです。しかし this SO post によると、単純に一重引用符で囲むのは安全ではないということです...だから私にはわかりません。
方法2
これが同じくらい安全かどうかはわかりませんが、実際のPGで準備された関数を使用しているようです(100%安全だと思います)。唯一の問題はRailsがコンソールに出力せず、SQL実行時間を含まないことです(これは私のプロファイリングツールを壊します)。
_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
_
同じように使用されます:
RawQuery.new.prepare('SELECT * FROM users WHERE name = $1', params[:name])
ある方法は別の方法よりも安全ですか?どちらも100%安全ですか?
私のアプリは常にRailsがSQLに関して機能するものをはるかに超えて拡張されており、完全に安全であることがわかっているすべてのプロジェクトに含めることができる優れたライブラリが必要です。
quote
の使用は安全です。 リンク先のページ の回答を読みましたが、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
メソッドは引用符を付けるだけではありません。始まりと終わり。
また、信頼できる引用を探していると言うので、ソースコード自体のコメントは、ユーザー入力の引用がこれらの関数の意図された目的であることを示唆しています。
# Quotes the column value to help prevent
# {SQL injection attacks}[http://en.wikipedia.org/wiki/SQL_injection].
def quote(value)
# Quotes strings for use in SQL input.
def quote_string(s) #:nodoc:
(コメントにはquote_string
を表示していますが、おそらくquote
を使用する必要があります。これは、データ型を把握して適切な処理を実行しようとします。)
ちなみに、これはあなたと同様の質問で、2014年に私からの回答があり、いくつかの選択肢もあります: Railsで動的バインディングを使用して生の更新SQLを実行する方法