Nic*_*nto 7 sql activerecord escaping ruby-on-rails
在rails源(https://github.com/rails/rails/blob/fe4b0eee05f59831e1468ed50f55fbad0ce11e1d/activerecord/lib/active_record/sanitization.rb#L112)中,有一种sanitize_sql_like方法(我希望)在使用它们之前清理字符串SQL LIKE
但是,我似乎无法使用它,因为Rails说该方法不存在.
我的字符串中有一个撇号,查询是
@query = "Joe's"
Model.where("lower(field) LIKE ?", "%#{@query}%")
Run Code Online (Sandbox Code Playgroud)
使用ActiveRecord::Base.sanitize没有帮助,因为查询没有结果.
我怎样才能逃脱@query并保持我的SQL安全?
我已经使用ActiveRecord :: Sanitization :: ClassMethods解决了同样的问题(在MySQL上)来正确清理用户输入.不幸的是,ActiveRecord :: Sanitization :: ClassMethods中定义的方法被声明为protected,因此它们只能在Model类的范围内访问.ActiveRecord :: Sanitization :: ClassMethods中定义的方法混合到所有Model类中,因此可以直接在Model的范围内使用它们.这要求您在模型上定义类/实例方法或scope(ActiveRecord范围)以使用它们,而不是像在示例中那样在外部使用它们.但是,在设计方面,最好将查询逻辑封装在模型中.
此解决方案还具有以下优点:不仅可以转义单引号字符,还可以转义将由SQL查询解释的其他字符,例如'%'字符(以及其他字符).这应该通过转义可能导致值被解释而不是被视为文字的其他字符来正确地防止SQL注入.还有一些额外的清理方法ActiveRecord::Sanitization::ClassMethods可用于在其他SQL查询上下文中嵌入用户输入(或其他受污染的输入).这是一个在MySQL上测试的工作解决方案.
class Model < ActiveRecord::Base
# Finds a Model by case-insensitive substring match on Model.field
#
# @param query [String] A value to use in the substring match.
# @return [ActiveRecord::Relation] An `Relation` of `Model`s whose
# `field` includes the `query` substring.
scope :find_by_field_substring, ->(query) do
where(arel_table[:field].matches("%#{sanitize_sql_like(query)}%"))
end
end
Run Code Online (Sandbox Code Playgroud)
然后,您可以scope像这样访问:
Model.find_by_field_substring "Joe's"
=> #<ActiveRecord::Relation [#<Model id: 1, field: "Joe's">]>
Run Code Online (Sandbox Code Playgroud)
ActiveRecord范围和ActiveRecord :: Relations的使用都有很好的文档记录,但可能只在较新版本的Rails中可用.
请注意,您的数据库可能需要方法的第二个参数sanitize_sql_like来指定与"\"不同的转义字符.
另请注意,如果它在NO_BACKSLASH_ESCAPES模式下运行,则这样的转义对MySQL不起作用,因为它强制使用不同的机制来转义值.如果您正在使用NO_BACKSLASH_ESCAPES模式,请参阅此答案.
我没有测试过这个部分,但是使用Arel(位于ActiveRecord下面的SQL AST构建器),可能也可以使用初始示例中建议的样式,只要它在Model类中定义.
class Model < ActiveRecord::Base
scope :find_by_field_substring, ->(query) do
where("lower(field) LIKE ?", "%#{sanitize_sql_like(query)}%")
end
end
Run Code Online (Sandbox Code Playgroud)
如果使用where得当,它会自动转义输入
@query = "Joe's"
Model.where("lower(field) LIKE ?", "%#{@query}%")
Run Code Online (Sandbox Code Playgroud)
请注意,您的查询是错误的。您有一个lower()运算符,然后您传递一个非小写的输入。查询将始终返回 0。
而且,lower()会降低数据库使用索引的能力。在大多数数据库中,LIKE 已经不区分大小写(PostgreSQL 除外,您应该使用ILIKE)。
query = "Joe's"
Model.where("field LIKE ?", "%#{query}%")
Run Code Online (Sandbox Code Playgroud)
或者
query = "Joe's"
Model.where("field ILIKE ?", "%#{query}%")
Run Code Online (Sandbox Code Playgroud)
这是真实数据库的真实示例。正如您所看到的,输入在最终的 SQL 中被正确转义。
> query = "Joe's"
> User.where("lower(email) LIKE ?", "%#{query}%")
User Load (4.4ms) SELECT "users".* FROM "users" WHERE (lower(email) LIKE '%Joe''s%')
=> #<ActiveRecord::Relation []>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5766 次 |
| 最近记录: |