【问题标题】:How to sanitize sql fragment in Rails如何在 Rails 中清理 sql 片段
【发布时间】: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 派生类中调用,无需更改可见性
  • 这是一个很好且有效的观点。当我使用某人的私有或受保护方法时,我只会畏缩。

标签: sql ruby-on-rails sanitize


【解决方案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_conditionssanitize_sql。这三个人做着完全相同的事情。

    sanitize_sql_for_conditions

    接受一个数组、散列或 SQL 条件字符串并清理 将它们放入一个有效的 SQL 片段中用于 WHERE 子句

    在 ActiveRecord 中你也有

    sanitize_sql_for_assignment哪个

    接受一个数组、散列或 SQL 条件字符串并对其进行清理 用于 SET 子句的有效 SQL 片段。

    • 上述方法默认包含在 ActiveRecord::Base 中,因此包含在任何 ActiveRecord 模型中

    docs


    不过,在 ActionController 中,您有 ActionController::Parameters,它允许您

    选择哪些属性应该被列入白名单以进行大规模更新和 从而防止意外暴露不应该暴露的东西。 为此提供了两种方法:requirepermit

       

    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 的神秘面纱! :)

    【讨论】:

    • requirepermit 是针对 SQL 注入清理参数,还是仅验证它们的存在?
    • 它进行零消毒,只是验证存在
    • @Matt:Jimmy 是对的,requirepermit 自己不要进行任何消毒。但是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://stackoverflow.com/a/53948665/165673

    【讨论】:

      猜你喜欢
      • 2011-11-01
      • 2016-03-27
      • 2012-05-13
      • 1970-01-01
      • 2010-11-25
      • 2023-03-15
      • 1970-01-01
      • 2013-07-26
      • 1970-01-01
      相关资源
      最近更新 更多