2017-08-10 11 views
1

私は、文字列の配列を受け入れるRubyメソッド(例えば、["EG", "K", "C"])を作成しようとしています。icao_codeフィールドのいずれかで始まるデータベーステーブルからすべてのレコードを返します。それらの文字列(例えば、KORD、EGLL、CYVRはすべて一致します)。配列の長さは変化し、ユーザーが入力するので、消さなければなりません。Ruby on Railsの任意の長さのLIKE句

1つの文字列に対してはAirport.where("icao_code LIKE ?", "#{icao_start}%")のようなことができますが、任意の数の文字列に対して検索する必要があるため、その構文は使用できません。

今のところ、次のように働いて、それをotの:

def in_region(icao_starts) 
    where_clause = icao_starts.map{|i| "icao_code LIKE '#{i}%'"}.join(" OR ") 
    return Airport.where(where_clause) 
end 

しかし、私はそれがSQLインジェクションの脆弱性だろう疑うので、ビットは、信頼できないユーザの入力で、このような設定を使用して心配です。

より安全な方法で同じ結果を得るためのより良い方法はありますか?これは?プレースホルダ(?潜在的に非常に長い)文字列を構築します

def in_region(icao_starts) 
    where_clause = "icao_code LIKE '#?%' OR " * icao_starts.length 
    return Airport.where(where_clause.sub(/\ OR\ $/, ''), *icao_starts) 
end 

答えて

1

あなたはこのような何かを考えることができます。 *icao_startsはその配列をwhere句の引数に展開するので、各?は安全に置き換えられます。 sub(/\ OR\ $/, '')は、最終的にはORを切り捨てます(必要に応じて1=0を追加できます)。

私があなただったら、私はまた、あなたが何かをする前に、icao_starts.uniqを実行するいくつかの賢明な上側の長さの制限で配列を切り捨て、も許可される値のホワイトリストが(ああ、私は、ユーザーを考えた、ということを忘れているだろう空港コードで検索していました)。それはかなり間違いないはずです。

+1

を取り除くために正規表現を使用していません。私は 'map {| s |小文字を入力するユーザーを処理し、アルファベット以外の文字を削除するには、s.upcase.tr {"^ A-Z"、 ""}} 'を使用します。 – bogardpd

1

あなたは、SQLクエリにユーザー入力を補間しないことが正しいです。これは危険であり、コードがSQLI攻撃に対して脆弱になります。

def in_region(icao_starts) 
    conditions = icao_starts.map { "icao_code LIKE ?"} 
    Airport.where(conditions.join(' OR '), *icao_starts.map { |name| "#{name}%"}) 
end 

それはbogardpdのソリューションよりもかなり似ていますが、最後の「OR」 `compact`と` uniq`を使用して終了