【发布时间】:2014-11-23 12:33:21
【问题描述】:
我正在尝试编写 LIKE 查询。
我读到纯字符串查询并不安全,但是我找不到任何说明如何编写安全 LIKE Hash Query 的文档。
有可能吗?我应该手动防御 SQL 注入吗?
【问题讨论】:
标签: ruby activerecord ruby-on-rails-4
我正在尝试编写 LIKE 查询。
我读到纯字符串查询并不安全,但是我找不到任何说明如何编写安全 LIKE Hash Query 的文档。
有可能吗?我应该手动防御 SQL 注入吗?
【问题讨论】:
标签: ruby activerecord ruby-on-rails-4
为确保您的查询字符串得到正确清理,请使用数组或哈希查询语法来描述您的条件:
Foo.where("bar LIKE ?", "%#{query}%")
或:
Foo.where("bar LIKE :query", query: "%#{query}%")
如果query 可能包含% 字符,那么您需要先使用sanitize_sql_like 清理query:
Foo.where("bar LIKE ?", "%#{sanitize_sql_like(query)}%")
Foo.where("bar LIKE :query", query: "%#{sanitize_sql_like(query)}%")
【讨论】:
%。这不是任意的“SQL 注入”,但仍然可能会意外运行。
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 读起来更好,IMO。
对于 PostgreSQL,它将是
Foo.where("bar ILIKE ?", "%#{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 替换为您的型号名称
【讨论】:
你可以的
MyModel.where(["title LIKE ?", "%#{params[:query]}%"])
【讨论】: