Rails brakeman warning of sql injection

我们两清 提交于 2019-12-05 10:39:46

After some kind of research here is what I would use. There is a method called sanitize_sql_array (ref), you can use it to escape statements by passing an sql string and replacement values to it like:

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

If we'd pass a table name to this method it will also escape it, but will apply a quote method of ActiveRecord::Base.connection object on a value, which is used to escape variables, but not table names. Maybe sometimes it will work, but it failed for me when I was using PostrgreSQL, because quote method uses single quotes, but PostgreSQL requires double-quotation for table names.

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 object also has a method quote_table_name, which could be separately applied on table names, to make sure that they are escaped + use sanitize_sql_array for user 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)
}

Or you could actually just use sanitize on user.id instead of wrapping everything in sanitize_sql_array method call (#{sanitize(user.id)}).

By the way, Brakeman won't already show any warnings, because query has been moved to a variable. Brakeman literally parses your code as is and it does not know about a variable and it's content. So all this thing is just to make yourself sure that everything is being escaped.

Just to shut up Brakeman you could just move a query to a variable:

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)
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!