Я пытаюсь написать запрос LIKE.
Я читал, что чистые строковые запросы небезопасны, однако я не смог найти никакой документации, объясняющей, как написать безопасный LIKE Hash Query.
Является ли это возможным? Должен ли я вручную защищаться от внедрения SQL-кода?
ruby
activerecord
ruby-on-rails-4
Гал Вайс
источник
источник
Ответы:
Чтобы гарантировать, что ваша строка запроса будет правильно обработана, используйте массив или синтаксис хеш-запроса для описания ваших условий:
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
теги ...sanitize_sql_like()
.Используя 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
читается лучше, ИМО.Для PostgreSQL это будет
Foo.where("bar ILIKE ?", "%#{query}%")
источник
Ты можешь сделать
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
на название вашей моделиисточник