SQL-инъекция Ruby on Rails - построение запроса - PullRequest
0 голосов
/ 04 декабря 2018

Я разрешаю все SQL-инъекции в системе и обнаружил что-то, что не знаю, как лечить.

Может кто-нибудь мне помочь?

Вот мойМетод

def get_structure()
   #build query
   sql = %(
           SELECT pc.id AS "product_id", pc.code AS "code", pc.description AS "description", pc.family AS "family", 
                  p.code AS "father_code", p.description AS "father_description", 
                  p.family AS "father_family"
           FROM products pc
           LEFT JOIN imported_structures imp ON pc.id = imp.product_id
           LEFT JOIN products p ON imp.product_father_id = p.id
           WHERE pc.enable = true AND p.enable = true
   )
   #verify if there is any filter
   if !params[:code].blank?
     sql = sql + " AND UPPER(pc.code) LIKE '%#{params[:code].upcase}%'"
   end
   #many other parameters like the one above
   #execute query
   str = ProductStructure.find_by_sql(sql)
end

Спасибо!

Ответы [ 2 ]

0 голосов
/ 04 декабря 2018

Вы можете использовать Arel, который вам не нужен и является базовым построителем запросов для ActiveRecord / Rails.например.

products = Arel::Table.new("products")
products2 = Arel::Table.new("products", as: 'p')
imported_structs = Arel::Table.new("imported_structures")
query = products.project(
  products[:id].as('product_id'),
  products[:code],
  products[:description], 
  products[:family], 
  products2[:code].as('father_code'),
  products2[:description].as('father_description'),
  products2[:family].as('father_family')).
  join(imported_structs,Arel::Nodes::OuterJoin).
    on(imported_structs[:product_id].eq(products[:id])).
  join(products2,Arel::Nodes::OuterJoin).
    on(products2[:id].eq(imported_structs[:product_father_id])).
  where(products[:enable].eq(true).and(products2[:enable].eq(true)))
if !params[:code].blank?
  query.where(
     Arel::Nodes::NamedFunction.new('UPPER',[products[:code]])
       .matches("%#{params[:code].to_s.upcase}%")
  )
end

Результат SQL: (с params[:code] = "' OR 1=1 --test")

SELECT 
  [products].[id] AS product_id, 
  [products].[code], 
  [products].[description], 
  [products].[family], 
  [p].[code] AS father_code, 
  [p].[description] AS father_description, 
  [p].[family] AS father_family 
FROM 
  [products] 
  LEFT OUTER JOIN [imported_structures] ON [imported_structures].[product_id] = [products].[id] 
  LEFT OUTER JOIN [products] [p] ON [p].[id] = [imported_structures].[product_father_id] 
WHERE 
  [products].[enable] = true AND 
  [p].[enable] = true  AND 
  UPPER([products].[code]) LIKE N'%'' OR 1=1 --test%'

Для использования

ProductStructure.find_by_sql(query.to_sql)

Я предпочитаю Arel, если доступно, более String запрашивает потому что:

  • он поддерживает экранирование
  • он использует ваш существующий адаптер подключения для sytnax (поэтому он переносим, ​​если вы меняете базы данных)
  • он встроенкод, поэтому порядок операторов не имеет значения
  • он гораздо более динамичен и удобен в обслуживании
  • он изначально поддерживается ActiveRecord
  • вы можете построить любой сложный запрос, который вы можете себе представить (включаясложные соединения, CTE и т. д.)
  • все еще очень читабельно
0 голосов
/ 04 декабря 2018

Необходимо преобразовать это значение в заполнитель (?) и добавить данные в качестве отдельного аргумента.find_by_sql может принимать массив:

def get_structure
   #build query
   sql = %(SELECT...)
   query = [ sql ]

   if !params[:code].blank?
     sql << " AND UPPER(pc.code) LIKE ?"
     query << "%#{params[:code].upcase}%"
   end

   str = ProductStructure.find_by_sql(query)
end

Обратите внимание, используйте << для String вместо +=, когда вы можете избежать копирования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...