我的模型中有一个范围:

scope :assigned_to_user, ->(user) {
task_table = UserTask.table_name

    joins("INNER JOIN #{task_table}
          ON  #{task_table}.user_id = #{user.id}
          AND (#{task_table}.type_id = #{table_name}.type_id)
          AND (#{task_table}.manager_id = #{table_name}.manager_id)
        ")
}

因此,在运行刹车员报告后,我会收到以下警告:
assigned_to_user | SQL Injection | Possible

所以我尝试了以下方法:
scope :assigned_to_user, ->(user) {
    task_table = UserTask.table_name

        joins(ActiveRecord::Base::sanitize("INNER JOIN #{task_table}
              ON  #{task_table}.user_id = #{user.id}
              AND (#{task_table}.type_id = #{table_name}.type_id)
              AND (#{task_table}.manager_id = #{table_name}.manager_id)
            "))
    }

这对我不起作用,因为它在sql的前面和后面添加了'(撇号)。因此,当我将其用作返回一些结果的查询的一部分并且应用此范围时,它将生成错误的sql。

我也尝试过这个:
scope :assigned_to_user, ->(user) {
    task_table = UserTask.table_name

        joins("INNER JOIN #{task_table}
              ON  #{task_table}.user_id = ?
              AND (#{task_table}.type_id = #{table_name}.type_id)
              AND (#{task_table}.manager_id = #{table_name}.manager_id)
            ", user.id)
    }

甚至不构建该语句。并尝试了其他一些不起作用,甚至不值得一提的东西。有人知道如何解决此问题吗?

最佳答案

经过某种研究后,这里是我会用的。
有一种称为sanitize_sql_array(ref)的方法,您可以通过将sql字符串和替换值传递给它来转义语句,例如:

sanitize_sql_array(['user_id = :user_id', user_id: 5])
# => "user_id = 5"

如果我们将表名传递给此方法,它将也对其进行转义,但是将对值使用quote对象的ActiveRecord::Base.connection方法,该值用于转义变量,但不转义表名。也许有时它可以工作,但是当我使用PostrgreSQL时,它对我失败了,因为quote方法使用单引号,但是PostgreSQL需要对表名使用双引号。
sanitize_sql_array([
  'INNER JOIN :table_name ON :table_name.user_id = :user_id',
  { table_name: 'users', user_id: 5 }
])
# => "INNER JOIN 'users' ON 'users'.user_id = 5"
connection对象还具有方法quote_table_name,可以将其单独应用于表名,以确保对它们进行转义+将sanitize_sql_array用作用户ID。
scope :assigned_to_user, -> (user) {
  task_table = connection.quote_table_name(UserTask.table_name)
  current_table = connection.quote_table_name(table_name)
  sanitized_sql = sanitize_sql_array([
    "INNER JOIN #{task_table}
    ON  #{task_table}.user_id = :user_id
    AND (#{task_table}.type_id = #{current_table}.type_id)
    AND (#{task_table}.manager_id = #{current_table}.manager_id)",
    { user_id: user.id }
  ])
  joins(sanitized_sql)
}

或者,您实际上可以只在sanitize上使用user.id,而不是将所有内容包装在sanitize_sql_array方法调用(#{sanitize(user.id)})中。

顺便说一句,Brakeman不会显示任何警告,因为查询已移至变量。 Brakeman照原样解析您的代码,并且它不知道变量及其内容。因此,所有这一切只是为了确保自己已逃脱一切。

只需关闭Brakeman,您就可以将查询移至变量:
scope :assigned_to_user, -> (user) {
  task_table = UserTask.table_name
  query = "INNER JOIN #{task_table}
          ON  #{task_table}.user_id = #{user.id}
          AND (#{task_table}.type_id = #{table_name}.type_id)
          AND (#{task_table}.manager_id = #{table_name}.manager_id)"
  joins(query)
}

关于sql - Rails Brakeman警告SQL注入(inject),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27853371/

10-11 16:06