我正在尝试编写LIKE查询。
我读到纯字符串查询并不安全,但是找不到任何说明如何编写安全的LIKE哈希查询的文档。
可能吗?我应该手动防御SQL注入吗?
Answers:
为确保正确清理查询字符串,请使用数组或哈希查询语法来描述您的条件:
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元字符。让我们举一个更现实的例子,%...%:字符串具有类似路径的结构,并且您尝试match /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
IMO读起来更好。
如果有人对嵌套关联执行搜索查询,请尝试以下操作:
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
用模型名称替换