Я читал об этом в течение некоторого времени в разных SO-потоках, руководствах и т.д., но все ответы противоречивы и противоречивы.
Кажется, существует много подобных методов, и многие ответы говорят, что они используют другой.
-
sanitize
-
sanitize_conditions
-
sanitize_sql
-
sanitize_sql_array
-
sanitize_sql_for_assignment
-
sanitize_sql_for_conditions
-
sanitize_sql_hash
-
sanitize_sql_hash_for_assignment
-
sanitize_sql_hash_for_conditions
-
sanitize_sql_like
Я пытаюсь написать адаптер "raw query", который позволяет запускать необработанные запросы Postgres, но позволяет мне вставлять мои собственные параметры, которые поступают из опасного пользовательского ввода.
Я не могу использовать AR в этих нескольких случаях, потому что я выполняю сложные вычисления lat/long, агрегированные функции, сложные подзапросы и т.д.
До сих пор я пробовал 2 подхода:
Метод 1
Для этого метода я не знаю, является ли sanitize
лучшим вариантом выше, или если он будет работать в 100% случаев... (я использую только Postgres)
class RawQuery
def exec(prepared, *params)
prepared = query.dup
params.flatten.each_with_index do |p, i|
prepared.gsub!("$#{i + 1}", ActiveRecord::Base.sanitize(p))
end
ActiveRecord::Base.connection.exec_query(prepared)
end
end
Пример тривиального использования (обычно это было бы не так просто, или я бы просто использовал AR):
RawQuery.new.exec('SELECT * FROM users WHERE name = $1', params[:name])
Кроме того, кажется, что sanitize
делегирует quote
. Но в соответствии с этим SO post в нем говорится, что просто обертывание вещей одинарными кавычками небезопасно... поэтому я понятия не имею.
Метод 2
Я не уверен, что это так же безопасно, но, похоже, использует фактическую подготовленную PG-функцию (которая, как я полагаю, на 100% безопасна). Единственная проблема заключается в том, что рельсы не распечатывают ее на консоль, а также не включают время выполнения SQL (которое разбивает мои инструменты профилирования).
class RawQuery
def prepare(query, *params)
name = "raw_query_#{SecureRandom.uuid.gsub('-', '')}"
connection = ActiveRecord::Base.connection.raw_connection
connection.prepare(name, query)
connection.exec_prepared(name, params)
end
end
Используется так же:
RawQuery.new.prepare('SELECT * FROM users WHERE name = $1', params[:name])
Является ли один метод более безопасным над другим? Защищены ли они на 100%?
Мои приложения всегда расширяются далеко за пределами того, что Rails может использовать SQL-мудрый, и мне нужна хорошая библиотека, которую я могу включить во все мои проекты, которые, как я знаю, абсолютно безопасны.