【问题标题】:How to sanitize raw SQL in Rails 4如何在 Rails 4 中清理原始 SQL
【发布时间】:2016-03-27 22:47:46
【问题描述】:

在 Rails 3 中,我可以使用sanitize_sql_array 来清理那些偶尔需要原始 SQL 查询的原始 SQL。但这似乎已在 Rails 4 中被删除,或者没有被删除,而是移至 ActiveRecord::Sanitization。但是,我现在不知道如何调用sanitize_sql_array,那么在 Rails 4 中清理原始 SQL 的最佳方法是什么?

我想澄清一下,我在这里谈论的是完整的原始 SQL 查询,而不是使用 Rail 的模型。我知道这不是最佳实践,这正是我必须为这个特定查询做的,因为它不能用 Rails 漂亮的 ActiveRecord 接口表示(相信我,我试过了)。

这是一个示例调用,它显然比我的查询实际看起来更简单:

query = "SELECT * FROM users 
LEFT OUTER JOIN posts ON users.id=posts.user_id
AND posts.topic_id = '#{topic.id}'" 
# ^- Obviously bad and very vulnerable, this is what we're trying to fix
ActiveRecord::Base.connection.select_all(query)

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-3 postgresql ruby-on-rails-4


    【解决方案1】:

    如果您确实需要编写原始 SQL,可以使用 quote 对其进行清理:

    conn = ActiveRecord::Base.connection
    name = conn.quote("John O'Neil")
    title = conn.quote(nil)
    query = "INSERT INTO users (name,title) VALUES (#{name}, #{title})"
    conn.execute(query)
    

    【讨论】:

      【解决方案2】:

      Active Record docs 开始,清理 SQL 查询的最佳方法是避免将我们自己的条件构建为纯字符串,换句话说,将参数直接插入到查询中,像这样:

      User.find_by("user_name = '#{user_name}' AND password = '#{password}'")
      

      改为使用数组或哈希条件。

      数组条件:

      Client.where("orders_count = ? AND locked = ?", params[:orders], false)
      

      哈希条件:

      Client.where(is_active: true)
      

      一个清晰的例子:

      class User < ActiveRecord::Base
        # UNSAFE - susceptible to SQL-injection attacks
        def self.authenticate_unsafely(user_name, password)
          where("user_name = '#{user_name}' AND password = '#{password}'").first
        end
      
        # SAFE
        def self.authenticate_safely(user_name, password)
          where("user_name = ? AND password = ?", user_name, password).first
        end
      
        # SAFE
        def self.authenticate_safely_simply(user_name, password)
          where(user_name: user_name, password: password).first
        end
      end
      

      以下是一些参考资料:

      【讨论】:

      • 嘿尼克,感谢您的回复,但我正在寻找一个适用于不通过 ActiveRecord 模型的原始 SQL 查询的答案。我已经更新了我的问题,以便更清楚地说明这一点。
      • @ColtonVoege 抱歉,我误解了这个问题。正如@gabrielhilal 所说,quote 是在不使用 ActiveRecord 模型的情况下清理原始 sql 查询的正确方法
      • 这个答案太错误了,使用'#{user_name}'对SQL注入是可敬的。
      • @Hardik 是的,你是对的。这就是为什么顶部有一条大写的评论:# UNSAFE - susceptible to SQL-injection attacks,也许你错过了:)
      • @Hardik 你能解释一下只使用引号是不安全的吗?我现在真的在为此苦苦挣扎,每一个答案都相互矛盾(例如,下面的答案说引用就足够了)。这是我试图解决的问题:stackoverflow.com/questions/41410752/rails-5-sql-injection
      【解决方案3】:

      quote 方法和其他 ActiveRecord::Base 清理方法已被弃用,并且从未成为公共 API 的一部分。

      https://github.com/rails/rails/issues/28947

      官方的消毒方法是

      http://api.rubyonrails.org/classes/ActiveRecord/Sanitization/ClassMethods.html

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-01
        • 2011-03-01
        • 2013-01-19
        • 2018-06-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多