如何正确参数化我的 postgresql 查询
How to properly parameterize my postgresql query
我正在尝试参数化我的 postgresql 查询,以防止 SQL 在 rails 应用程序的 ruby 中注入。 SQL 查询将根据输入在我的 table 中求和一个不同的值。
这是我的函数的简化版本:
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 注入,但在这种情况下我该如何防止呢?处理这种情况的最佳方法是什么?
编辑: 我添加了一个要从 table 中获取的额外列,以强调我不能使用 pick
来获取一个值。
find_by_sql
用于用单行文字 SQL 填充对象。但是我们可以使用 ActiveRecord 来完成其中的大部分,我们只需要一个列。要制作对象,请使用 select
. If you just want results use pluck
.
当您从一组固定的字符串中进行选择时,此代码中没有 SQL 注入的风险。使用 Arel.sql
传递一个你知道是安全的 SQL 文字。
def self.calculate_value(result_name)
sum_sql = case result_name
when "quantity"
"sum(amount)"
when "retail"
"sum(amount * price)"
when "wholesale"
"sum(amount * cost)"
end
sum_sql = Arel.sql(
"coalesce(cast(#{sum_sql} as double precision), 0) as #{result_name}"
)
return Table1
.group(:location)
# replace pluck with select to get Table1 objects
.pluck(:location, sum_sql)
end
我正在尝试参数化我的 postgresql 查询,以防止 SQL 在 rails 应用程序的 ruby 中注入。 SQL 查询将根据输入在我的 table 中求和一个不同的值。
这是我的函数的简化版本:
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 注入,但在这种情况下我该如何防止呢?处理这种情况的最佳方法是什么?
编辑: 我添加了一个要从 table 中获取的额外列,以强调我不能使用 pick
来获取一个值。
find_by_sql
用于用单行文字 SQL 填充对象。但是我们可以使用 ActiveRecord 来完成其中的大部分,我们只需要一个列。要制作对象,请使用 select
. If you just want results use pluck
.
当您从一组固定的字符串中进行选择时,此代码中没有 SQL 注入的风险。使用 Arel.sql
传递一个你知道是安全的 SQL 文字。
def self.calculate_value(result_name)
sum_sql = case result_name
when "quantity"
"sum(amount)"
when "retail"
"sum(amount * price)"
when "wholesale"
"sum(amount * cost)"
end
sum_sql = Arel.sql(
"coalesce(cast(#{sum_sql} as double precision), 0) as #{result_name}"
)
return Table1
.group(:location)
# replace pluck with select to get Table1 objects
.pluck(:location, sum_sql)
end