LIKEクエリを作成しようとしています。
純粋な文字列のクエリは安全ではないことを読みましたが、安全なLIKEハッシュクエリの記述方法を説明するドキュメントは見つかりませんでした。
出来ますか?SQLインジェクションに対して手動で防御する必要がありますか?
回答:
クエリ文字列が適切にサニタイズされるようにするには、配列またはハッシュクエリ構文を使用して条件を記述します。
Foo.where("bar LIKE ?", "%#{query}%")
または:
Foo.where("bar LIKE :query", query: "%#{query}%")
キャラクターquery
が含まれている可能性がある場合は、最初%
に消毒する必要があります。query
sanitize_sql_like
Foo.where("bar LIKE ?", "%#{sanitize_sql_like(query)}%")
Foo.where("bar LIKE :query", query: "%#{sanitize_sql_like(query)}%")
%
はクエリ文字列でエスケープできません。これは恣意的な「SQLインジェクション」ではありませんが、それでも予期せず機能する可能性があります。
%
ため、エスケープしたくありません。エスケープした場合、結果は基本的に通常のクエリになります。%
LIKE
%
=
query
おり、多くの場合、query
変数の文字列と文字通り一致させ、query
LIKEメタ文字の使用を許可しません。%...%というより現実的な例を見てみましょう。文字列はパスのような構造を持っており、を一致させようとします/users/#{user.name}/tags/%
。これで、ユーザー名をに設定するとfr%d%
、タグを監視できるようにfred
なりfrida
ます...
Arelを使用すると、次の安全でポータブルなクエリを実行できます。
title = Model.arel_table[:title]
Model.where(title.matches("%#{query}%"))
Model.where(title.matches("%#{query}%").not)
生成されたSQLは少しぎこちないですが、動作します:WHERE (NOT (`models`.`title` LIKE '%foo%'))
Model.where(title.does_not_match("%#{query}%"))
。生成: WHERE (`models`.`title` NOT LIKE '%foo%')
%
:信頼できない入力に >> ActiveRecord::VERSION::STRING => "5.2.3" >> field = Foo.arel_table[:bar] >> Foo.where(field.matches('%')).to_sql => "SELECT `foos`.* FROM `foos` WHERE `foos`.`bar` LIKE '%'"
Model.where.not(title.matches("%#{query}%"))
。does_not_match
でも、IMOの方が読みやすいです。
できるよ
MyModel.where(["title LIKE ?", "%#{params[:query]}%"])
ネストされた関連付けで検索クエリを実行している人がいる場合は、次のことを試してください。
Model.joins(:association).where(
Association.arel_table[:attr1].matches("%#{query}%")
)
複数の属性については、これを試してください。
Model.joins(:association).where(
AssociatedModelName.arel_table[:attr1].matches("%#{query}%")
.or(AssociatedModelName.arel_table[:attr2].matches("%#{query}%"))
.or(AssociatedModelName.arel_table[:attr3].matches("%#{query}%"))
)
AssociatedModelName
モデル名に置き換えることを忘れないでください