安全ActiveRecord之类的查询


Answers:


166

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

Foo.where("bar LIKE ?", "%#{query}%")

要么:

Foo.where("bar LIKE :query", query: "%#{query}%")

如果有可能的是,query可能包括%字符,那么你需要消毒querysanitize_sql_like第一:

Foo.where("bar LIKE ?", "%#{sanitize_sql_like(query)}%")
Foo.where("bar LIKE :query", query: "%#{sanitize_sql_like(query)}%")

这无法%在查询字符串中转义。它不是任意的“ SQL注入”,但可能仍会意外运行。
贝尼·

@ BeniCherniavsky-Paskin:这就是重点,您不想转义%因为语法的%一部分LIKE。如果逃脱了,%那么结果基本上将是正常=查询。
spickermann '17

1
正确,您想在模式模板中使用%通配符,但该模式已用query变量参数化,并且在许多情况下,您想按字面上地匹配query变量中的字符串,不允许query使用LIKE元字符。让我们举一个更现实的例子,%...%:字符串具有类似路径的结构,并且您尝试match /users/#{user.name}/tags/%。现在,如果我将用户名设置为fr%d%,我将可以观察fredfrida标记...
Beni Cherniavsky-Paskin

2
好的,我想要的是将此问题与stackoverflow.com/questions/5709887/…结合使用,这表明sanitize_sql_like()
贝尼·切尔尼亚夫斯基-帕斯金

2
@ BeniCherniavsky-Paskin现在,我了解您来自何处,而您是对的。我更新了答案以解决该问题。
spickermann '17

34

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

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

1
这是首选的解决方案,因为Arel是sql-db不可知的,并且具有一些内部输入清除功能。就代码风格而言,恕我直言,它也更加清晰和一致。
Andrew Moore

您如何否定这个?(即不喜欢)Model.where(title.matches("%#{query}%").not)有效,尽管生成的SQL有点尴尬:WHERE (NOT (`models`.`title` LIKE '%foo%'))
Noach Magedman,

啊...找到了。 Model.where(title.does_not_match("%#{query}%"))。产生: WHERE (`models`.`title` NOT LIKE '%foo%')
Noach Magedman

小心-无法对%不受信任的输入进行消毒: >> 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 '%'"
vjt

@NoachMagedman或Model.where.not(title.matches("%#{query}%"))does_not_matchIMO读起来更好。
elquimista '19

7

对于PostgreSQL它将是

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

1

你可以做

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

1
@mikkeljuhl请仔细查看我的回答。
Santhosh

0

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

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用模型名称替换

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.