如何在 Rails 中清理 sql 片段
Posted
技术标签:
【中文标题】如何在 Rails 中清理 sql 片段【英文标题】:How to sanitize sql fragment in Rails 【发布时间】:2011-03-01 20:13:45 【问题描述】:我必须清理 sql 查询的一部分。我可以这样做:
class << ActiveRecord::Base
public :sanitize_sql
end
str = ActiveRecord::Base.sanitize_sql(["AND column1 = ?", "two's"], '')
但这并不安全,因为我暴露了受保护的方法。有什么更好的方法?
【问题讨论】:
你能给我们更多的背景信息吗?sanitize_sql
和朋友经常在 AR::Base 派生类中调用,无需更改可见性
这是一个很好且有效的观点。当我使用某人的私有或受保护方法时,我只会畏缩。
【参考方案1】:
ActiveRecord::Base.connection.quote
在 Rails 3.x 中发挥作用
【讨论】:
【参考方案2】:你可以使用:
ActiveRecord::Base::sanitize_sql(string)
【讨论】:
这代表ActiveRecord::Base.connection.quote
(至少在Rails 4中)
已弃用。新的消毒方法here。请参阅 Bryan 的 answer
我将此答案从已弃用的版本 (sanitize
) 更新为 Rails 6 的当前工作版本 (sanitize_sql
)。如果有人想全面了解所有消毒方法,我建议the docs。【参考方案3】:
这个问题没有指定答案必须来自ActiveRecord
,也没有指定应该是哪个版本的Rails。出于这个原因(并且因为它是***和少数几个)关于如何清理 Rails 中的参数的答案......
这里有一个适用于 Rails 4 的解决方案:
在ActiveRecord::Sanitization::ClassMethods
中有sanitize_sql_for_conditions 及其另外两个别名:
sanitize_conditions 和 sanitize_sql。这三个人做着完全相同的事情。
sanitize_sql_for_conditions
接受一个数组、散列或 SQL 条件字符串并清理 将它们放入一个有效的 SQL 片段中用于 WHERE 子句。
在 ActiveRecord 中你也有
sanitize_sql_for_assignment
哪个
上述方法默认包含在 ActiveRecord::Base 中,因此包含在任何 ActiveRecord 模型中。接受一个数组、散列或 SQL 条件字符串并对其进行清理 用于 SET 子句的有效 SQL 片段。
见docs
不过,在 ActionController 中,您有 ActionController::Parameters
,它允许您
选择哪些属性应该被列入白名单以进行大规模更新和 从而防止意外暴露不应该暴露的东西。 为此提供了两种方法:require 和 permit。
params = ActionController::Parameters.new(user: name: 'Bryan', age: 21 )
req = params.require(:user) # will throw exception if user not present
opt = params.permit(:name) # name parameter is optional, returns nil if not present
user = params.require(:user).permit(:name, :age) # user hash is required while `name` and `age` keys are optional
“参数魔法”称为强参数 (docs here),您可以使用它在控制器中清理参数,然后再将其发送到模型。
上述方法默认包含在ActionController::Base
中,因此包含在任何 Rails 控制器中。
我希望这对任何人都有帮助,哪怕只是为了学习和揭开 Rails 的神秘面纱! :)
【讨论】:
require
和 permit
是针对 SQL 注入清理参数,还是仅验证它们的存在?
它进行零消毒,只是验证存在
@Matt:Jimmy 是对的,require
和 permit
自己不要进行任何消毒。但是ActionController::Parameters.new
进行了清理,因此您的所有控制器都应该已经清理了所有参数。稍后有时间我会更新我的答案,因为我还发现了这个非常酷的 gem,叫做 rails-html-sanitizer github.com/rails/rails-html-sanitizer
谢谢布莱恩。我正在向控制器发送大量 JSON,并且正在处理 3 秒以上的响应时间。我可以通过消除 JSON 中的冗余将这些时间减少到 2 秒,并通过不实例化 ActiveRecord 对象进一步将其降低到 500 毫秒以下。只是想确定我暴露了安全风险!
请注意,上面的清理方法是受保护的类方法,因此您需要从 AR 类中调用它们,或者通过您自己的 AR 类中的公共类方法公开它们。【参考方案4】:
从 rails 5 开始,推荐的方法是使用:ActiveRecord::Base.connection.quote(string)
如此处所述:https://github.com/rails/rails/issues/28947
ActiveRecord::Base::sanitize(string)
已弃用
【讨论】:
不推荐。请改用 Bryan 的 answer 中的 sanitation api。【参考方案5】:请注意,在清理 SQL WHERE 条件时,最好的解决方案是 sanitize_sql_hash_for_conditions,因为它正确处理了 NULL 条件(例如,如果为 nil,则会生成 IS NULL
而不是 = NULL
属性已通过)。
由于某种原因,它在 Rails 5 中已被弃用。所以我推出了一个面向未来的版本,请参见此处:https://***.com/a/53948665/165673
【讨论】:
以上是关于如何在 Rails 中清理 sql 片段的主要内容,如果未能解决你的问题,请参考以下文章
以下代码片段是不是容易受到 Rails 5 中 SQL 注入的影响?
在 Rails 上为连接、限制、选择等(不是条件)的 SQL 片段安全地转义字符串
Ruby on Rails:不使用 find 时如何为 SQL 清理字符串?
如何在 Rails 中链接原始 SQL 查询或如何从 Rails 中的原始 SQL 查询返回 ActiveRecord_Relation?