LIKEクエリを作成しようとしています。
純粋な文字列のクエリは安全ではないことを読みましたが、安全なLIKEハッシュクエリの記述方法を説明するドキュメントは見つかりませんでした。
出来ますか?SQLインジェクションに対して手動で防御する必要がありますか?
回答:
クエリ文字列が適切にサニタイズされるようにするには、配列またはハッシュクエリ構文を使用して条件を記述します。
Foo.where("bar LIKE ?", "%#{query}%")
または:
Foo.where("bar LIKE :query", query: "%#{query}%")
キャラクターqueryが含まれている可能性がある場合は、最初%に消毒する必要があります。querysanitize_sql_like
Foo.where("bar LIKE ?", "%#{sanitize_sql_like(query)}%")
Foo.where("bar LIKE :query", query: "%#{sanitize_sql_like(query)}%")
%はクエリ文字列でエスケープできません。これは恣意的な「SQLインジェクション」ではありませんが、それでも予期せず機能する可能性があります。
%ため、エスケープしたくありません。エスケープした場合、結果は基本的に通常のクエリになります。%LIKE%=
queryおり、多くの場合、query変数の文字列と文字通り一致させ、queryLIKEメタ文字の使用を許可しません。%...%というより現実的な例を見てみましょう。文字列はパスのような構造を持っており、を一致させようとします/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モデル名に置き換えることを忘れないでください