Rails 5.2.3 上的危险查询方法弃用警告

Dangerous query method deprecation warning on Rails 5.2.3

我正在将我的 Rails 应用程序升级到 5.2.3

我在我的应用程序中使用了以下代码。

MyModel.order('LOWER(name) ASC')

它引发了以下弃用警告:

DEPRECATION WARNING: Dangerous query method (method whose arguments are used as raw SQL) called with non-attribute argument(s): "LOWER(name)". Non-attribute arguments will be disallowed in Rails 6.0. This method should not be called with user-provided values, such as request parameters or model attributes. Known-safe values can be passed by wrapping them in Arel.sql()

我已经按照弃用警告的建议更改了以上内容并且警告消失了:

MyModel.order(Arel.sql('LOWER(name) ASC'))

我浏览了相关讨论here。似乎引入此更改是为了禁止 SQL 注入。

但是订单子句 LOWER(name) ASC 不包含任何用户输入。为什么这个排序被认为是不安全的?这是预期的行为还是我在这里遗漏了什么?

这是有意为之的行为,您链接到正确的讨论,这正是它的本质。我可以 re-elaborate 多说一点,这样很容易理解。

首先,re-explainingsql注入,仅供参考,这样做:

MyModel.order('LOWER(name) ASC')

意味着人们可以在订单函数中传递任意字符串,该字符串可能包含列名and/or 用户输入的订单类型。

现在假设,您的 Web 应用程序中有一个下拉列表,用户可以在其中选择列,而另一个用户可以在其中选择 desc 或 asc 并提交。数据。

控制器动作可能是:

order_sql = "#{params[:column_name]} #{params[:column_order]}"

这正是可以进行 sql 注入的地方,恶意用户可以编辑表单提交数据,而不是在 column_order 参数中发送 ascdesc ,他可以发送一些 sql 脚本,例如:asc; delete from table_name_user_guessed_or_knows 引起 SQL 注入,这就是为什么 rails 希望用户在使用 sql 时要谨慎.并允许 Arel.

用户的安全 sql

现在是第二部分,为什么允许输入name asc而不允许输入LOWER(name) asc

弃用警告:

DEPRECATION WARNING: Dangerous query method (method whose arguments are used as raw SQL) called with non-attribute argument(s): "LOWER(name) asc". Non-attribute arguments will be disallowed in Rails 6.0. This method should not be called with user-provided values, such as request parameters or model attributes. Known-safe values can be passed by wrapping them in Arel.sql()

关注单词:non-attribute argument(s),非属性参数是任何不是属性的东西,无论是在末尾附加的任何额外的sql SQL 注入或对属性的某些方法调用,因为方法调用也可用于改变 SQL.

的预期行为

接下来,您问:

the order clause LOWER(name) ASC doesn't contains any user input

Rails 根本无法知道字符串是如何形成的,它只知道这是一个正在传递的字符串。这就是为什么它抱怨并希望开发人员保持谨慎。

这就是允许 name asc 的原因,因为它是简单的属性参数。虽然 LOWER(name) asc 正在抛出警告,因为它不是简单的属性参数,但这个参数有一个方法调用,可能用于 SQL 注入。
(显然,攻击者可能不会使用简单的LOWER 用于攻击的函数,而是他会使用一些特殊的函数,也许是他在之前的某个甚至同一个调用中用类似的注入方法定义的函数。