Estoy intentando escribir una consulta LIKE.
Leí que los requisitos de cadenas puras no son seguros, sin embargo, no pude encontrar ninguna documentación que explique cómo escribir LIKE Hash Query de forma segura.
¿Es posible? ¿Debo defenderme manualmente contra la inyección SQL?
ruby
activerecord
ruby-on-rails-4
Gal Weiss
fuente
fuente
Respuestas:
Para asegurarse de que su cadena de consulta se desinfecte adecuadamente, use la matriz o la sintaxis de consulta hash para describir sus condiciones:
Foo.where("bar LIKE ?", "%#{query}%")
o:
Foo.where("bar LIKE :query", query: "%#{query}%")
Si es posible que
query
pueda incluir el%
personaje, primero debe desinfectarquery
consanitize_sql_like
:Foo.where("bar LIKE ?", "%#{sanitize_sql_like(query)}%") Foo.where("bar LIKE :query", query: "%#{sanitize_sql_like(query)}%")
fuente
%
en la cadena de consulta. No es una "inyección SQL" arbitraria, pero aún puede funcionar inesperadamente.%
porque%
es parte de laLIKE
sintaxis. Si escapó%
, el resultado sería básicamente una=
consulta normal .query
variable, y en muchos casos desea hacer coincidir literalmente la cadena enquery
variable, no permitir elquery
uso de metacaracteres LIKE. Tomemos un ejemplo más realista de% ...%: las cadenas tienen una estructura similar a una ruta y usted intenta hacer coincidir/users/#{user.name}/tags/%
. Ahora bien, si yo arregle mi nombre de usuario a serfr%d%
, voy a ser capaz de observarfred
yfrida
's etiquetas ...sanitize_sql_like()
.Con Arel puedes realizar esta consulta segura y portátil:
title = Model.arel_table[:title] Model.where(title.matches("%#{query}%"))
fuente
Model.where(title.matches("%#{query}%").not)
funciona, aunque el SQL generado es un poco incómodo:WHERE (NOT (`models`.`title` LIKE '%foo%'))
Model.where(title.does_not_match("%#{query}%"))
. Genera:WHERE (`models`.`title` NOT LIKE '%foo%')
%
en la entrada que no se confía:>> 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
se lee mejor sin embargo, en mi opinión.Para PostgreSQL será
Foo.where("bar ILIKE ?", "%#{query}%")
fuente
Tu puedes hacer
MyModel.where(["title LIKE ?", "%#{params[:query]}%"])
fuente
En caso de que si alguien realiza una consulta de búsqueda en una asociación anidada, intente esto:
Model.joins(:association).where( Association.arel_table[:attr1].matches("%#{query}%") )
Para múltiples atributos, intente esto:
Model.joins(:association).where( AssociatedModelName.arel_table[:attr1].matches("%#{query}%") .or(AssociatedModelName.arel_table[:attr2].matches("%#{query}%")) .or(AssociatedModelName.arel_table[:attr3].matches("%#{query}%")) )
No olvide reemplazar
AssociatedModelName
con el nombre de su modelofuente