sql - sql注入(inject)的Rails brakeman警告

标签 sql ruby-on-rails ruby sql-injection brakeman

我的模型中有一个范围:

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)
        ")
}

所以在运行 brakeman report 之后我收到这个警告:

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"

如果我们将表名传递给此方法,它也会对其进行转义,但会应用 ActiveRecord::Base.connection 对象的 quote 方法值,用于转义变量,而不是表名。也许有时它会起作用,但是当我使用 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)
}

或者您实际上可以在 user.id 上使用 sanitize 而不是将所有内容包装在 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 - sql注入(inject)的Rails brakeman警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27853371/

相关文章:

android - SQLite ORDER BY 'yyyy-mm-dd' 格式的月份号

ruby-on-rails - 在 Rails 应用程序中使用 watchr 进行彩色输出

ruby-on-rails - Rails 将脚本作为后台作业执行

ruby-on-rails - 具有用户身份验证功能的 Rails Web 应用程序是否有 'template' ?

php - 检查一个表的ID是否用作另一个表的外键

php - 获取MYSQL中重复条目的最新数据

mysql - 更新一列中三个元素的组合

ruby-on-rails - Linux 中的 Rails 2 + Paperclip + ImageMagick 不起作用?

ruby-on-rails - 设计:我不能只显示当前用户锻炼

ruby - 将值深度嵌套到给定路径数组的哈希中