Как правильно параметризовать мой запрос postgresql

#postgresql #sql-injection

#postgresql #sql-инъекция

Вопрос:

Я пытаюсь параметризовать свой запрос postgresql, чтобы предотвратить внедрение SQL в мое приложение ruby on rails. SQL-запрос будет суммировать разные значения в моей таблице в зависимости от входных данных.

Вот упрощенная версия моей функции:

 def self.calculate_value(value)
    calculated_value = ""
    if value == "quantity"
        calculated_value = "COALESCE(sum(amount), 0)"
    elsif value == "retail"
        calculated_value = "COALESCE(sum(amount * price), 0)"
    elsif value == "wholesale"
        calculated_value = "COALESCE(sum(amount * cost), 0)"
    end
    
    query = <<-SQL
        select CAST(? AS DOUBLE PRECISION) as ? from table1
    SQL
    return Table1.find_by_sql([query, calculated_value, value])
end
 

Если я вызову calculate_value("retail") , он выполнит запрос следующим образом:

 select location, CAST('COALESCE(sum(amount * price), 0)' AS DOUBLE PRECISION) as 'retail' from table1 group by location
 

Это приводит к ошибке. Я хочу, чтобы он выполнялся без кавычек, подобных этому:

 select location, CAST(COALESCE(sum(amount * price), 0) AS DOUBLE PRECISION) as retail from table1 group by location
 

Я понимаю, что добавление цитат — это то, что предотвращает sql-инъекцию, но как я могу предотвратить это в этом случае? Каков наилучший способ справиться с этим сценарием?

ПРИМЕЧАНИЕ: это упрощенная версия запросов, которые я буду писать, и я хочу использовать find_by_sql .

Комментарии:

1. Вам нужны двойные кавычки для идентификаторов, одинарные кавычки или значения.

2. Псевдоним не может быть параметром. Более того, он должен быть постоянным — динамическая структура вывода не является детерминированной. Рекомендация — создайте 3 отдельных окончательных непараметризованных текста запроса и выберите один из них в зависимости от предоставленного параметра.

Ответ №1:

Подготовленный оператор не может изменять структуру запроса: имена таблиц или столбцов, порядок предложений, имена функций и так далее. Таким образом можно изменять только литералы.

Где находится SQL-инъекция? Вы не собираетесь вводить пользовательское значение в текст запроса. Вместо этого вы проверяете заданное значение по списку разрешенных и используете только свои собственные написанные части SQL. В этом случае нет опасности SQL-инъекции.


Я также хочу дать ссылку на эту статью. Безопасно создавать текст запроса динамически, если вы управляете всеми частями этого запроса. И это намного лучше для СУБД, чем какая-то интеллектуальная логика в запросе.