加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

ruby-on-rails – 使用Postgres强制转换将动态列名称安全地传递

发布时间:2020-12-16 19:23:02 所属栏目:百科 来源:网络整理
导读:我在我的应用程序中没有日期查询,我做了很多时间,我想抽出一些问题. 所以说我有一个带有DateTime starts_at字段的模型: Shift.where('starts_at::time ?','20:31:00.00')- SELECT "shifts".* FROM "shifts" WHERE (starts_at::time '20:31:00.00') 这正确地
我在我的应用程序中没有日期查询,我做了很多时间,我想抽出一些问题.

所以说我有一个带有DateTime starts_at字段的模型:

Shift.where('starts_at::time > ?','20:31:00.00')
-> SELECT "shifts".* FROM "shifts" WHERE (starts_at::time > '20:31:00.00')

这正确地返回所有大于20:31的’starts_at’值.

我想动态地将列名传递给查询,所以我可以这样做:

Shift.where('? > ?',"#{column_name}::time",'20:31:00.00').
-> SELECT "shifts".* FROM "shifts" WHERE ('starts_at::time' > '20:31:00.00')

在此示例中,这不起作用,因为搜索将starts_at :: time作为字符串执行,而不是作为具有时间转换的列.

如何安全地将column_name传入带有:: time cast的查询?虽然这不会接受用户输入,但我仍然希望确保考虑SQL注入.

解决方法

这比你最初想象的要复杂得多,因为标识符(列名,表名,…)和值(‘pancakes’,6,…)是SQL中具有不同引用规则甚至引用的非常不同的东西字符串(字符串的单引号,标准SQL中标识符的双引号,MySQL中标识符的反引号,SQL-Server中标识符的括号,……).如果您考虑像Ruby变量名称这样的标识符,以及像文字Ruby值这样的值,那么您就可以开始看到差异.

当你这样说时:

where('? > ?',...)

两个占位符都将被视为值(不是标识符)并被引用.为什么是这样? ActiveRecord无法知道哪个?应该是一个标识符(例如created_at列名),它应该是一个值(例如20:31:00.00).

数据库连接确实有一个专门用于引用列名的方法:

> puts ActiveRecord::Base.connection.quote_column_name('pancakes')
"pancakes"
=> nil

所以你可以这样说:

quoted_column = Shift.connection.quote_column_name(column_name)
Shift.where("#{quoted_name}::time > ?",'20:31:00.00')

这有点令人不愉快,因为我们在使用字符串插值来构建SQL时会退缩(或至少我们应该).但是,quote_column_name将处理column_name中任何狡猾或不安全的事情,因此这实际上并不危险.

你也可以说:

quoted_column = "#{Shift.connection.quote_column_name(column_name)}::time"
Shift.where("#{quoted_name} > ?",'20:31:00.00')

如果您并不总是需要将列名转换为时间.甚至:

clause = "#{Shift.connection.quote_column_name(column_name)}::time > ?"
Shift.where(clause,'20:31:00.00')

你也可以使用extract or one of the other date/time functions而不是类型转换,但你仍然会留下引用问题和一些有点引人注目的quote_column_name调用.

另一种选择是将column_name列入白名单,以便只允许特定的有效值.然后,您可以将安全column_name直接放入查询中:

if(!in_the_whitelist(column_name))
  # Throw a tantrum,hissy fit,or complain in your preferred fashion
end
Shift.where("#{column_name} > ?",'20:31:00.00')

这应该没问题,只要你没有任何时髦的专栏名称,如“必须吃早餐”或类似的东西,总是需要正确引用.您甚至可以使用Shift.column_names或Shift.columns来构建白名单.

使用白名单和quote_column_name可能是最安全的,但quote_column_name方法应该足够了.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读