类似查询的安全 ActiveRecord

Posted

技术标签:

【中文标题】类似查询的安全 ActiveRecord【英文标题】:Safe ActiveRecord like query 【发布时间】:2014-11-23 12:33:21 【问题描述】:

我正在尝试编写 LIKE 查询。

我读到纯字符串查询并不安全,但是我找不到任何说明如何编写安全 LIKE Hash Query 的文档。

有可能吗?我应该手动防御 SQL 注入吗?

【问题讨论】:

How to do a LIKE query in Arel and Rails?的可能重复 【参考方案1】:

为确保您的查询字符串得到正确清理,请使用数组或哈希查询语法来描述您的条件:

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%,我将能够观察到fredfrida 的标签... 好的,我想要将这个问题与***.com/questions/5709887/… 结合起来,这表明sanitize_sql_like() @BeniCherniavsky-Paskin 现在我明白你来自哪里,你是对的。我更新了我的答案来解决这个问题。 ? 值得一提的是 _ 和 \ 字符需要转义。【参考方案2】:

使用 Arel,您可以执行此安全且可移植的查询:

title = Model.arel_table[:title]
Model.where(title.matches("%#query%"))

【讨论】:

这是更可取的解决方案,因为 Arel 与 sql-db-agnostic 无关并且有一些内部输入清理。就代码风格而言,它也更加清晰和一致,恕我直言。 你如何否定这一点? (即不喜欢)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 '%'" @NoachMagedman 或Model.where.not(title.matches("%#query%"))does_not_match 读起来更好,IMO。【参考方案3】:

对于 PostgreSQL,它将是

Foo.where("bar ILIKE ?", "%#query%") 

【讨论】:

该字段必须是 citext 类型才能使不区分大小写的搜索工作。否则会和 LIKE 一样。【参考方案4】:

如果有人对嵌套关联执行搜索查询,请尝试以下操作:

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 替换为您的型号名称

【讨论】:

【参考方案5】:

你可以的

MyModel.where(["title LIKE ?", "%#params[:query]%"])

【讨论】:

@mikkeljuhl 请仔细看我的回答。

以上是关于类似查询的安全 ActiveRecord的主要内容,如果未能解决你的问题,请参考以下文章

在 Rails 中使用子字符串查询安全的方式

mongoDB常用命令与安全加固

mysql架构介绍

Elasticsearch 脚本安全使用指南

Elasticsearch 脚本安全使用指南

Exp9 web安全基础