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

Dangerous query method deprecation warning on Rails 5.2.3

提问人:user11350468 提问时间:6/23/2019 更新时间:6/23/2019 访问量:3088

问:

我正在将我的 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'))

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

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

Ruby-on-Rails SQL注入 Ruby-on-Rails-5.2

评论

3赞 mu is too short 6/23/2019
MyModel.order(引发弃用警告)只知道你正在向它传递一个字符串,它不知道字符串来自哪里或它包含什么。
3赞 user11350468 6/23/2019
@muistooshort 但它不会引发弃用警告MyModel.order('name')
0赞 mu is too short 6/24/2019
没错,发现得很好。
0赞 Mr. Tim 8/20/2021
我发现 PR 有列入白名单的表达,这有助于我更好地理解为什么有些论点触发了这一点,而另一些则没有:github.com/rails/rails/pull/27947/......例如:可以,但不是。这是因为简单的函数调用不会触发。但确实如此。order('count(id)')order('count(*)')count()*

答:

15赞 Zia Ul Rehman Mughal 6/23/2019 #1

这是预期的行为,你链接到正确的讨论,这正是它的本质。不过,我可以再详细阐述一下,这样就很容易理解了。

首先,重新解释sql注入,仅供参考,这样做:

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

意味着人们可以在订单函数中传递任何字符串,此字符串可能包含来自用户的列名和/或订单类型输入。

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

在控制器操作中,可能要做的是:

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

这正是 sql 注入可以发生的地方,恶意用户可以编辑表单提交数据,而不是发送 or in param,他可以发送一些 sql 脚本,如下所示: 导致 SQL 注入,这就是为什么 rails 希望用户在顺序函数中使用 sql 时要谨慎。并特别允许使用用户的安全 sql。ascdesccolumn_orderasc; delete from table_name_user_guessed_or_knowsArel

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

弃用警告如下:

弃用警告:使用非属性参数调用的危险查询方法(其参数用作原始 SQL)的方法:“LOWER(name) asc”。在 Rails 6.0 中将不允许使用非属性参数。不应使用用户提供的值(如请求参数或模型属性)调用此方法。可以通过将已知安全值包装在 Arel.sql() 中来传递它们

关注以下词语:非属性参数,非属性参数是任何非属性的东西,无论是在末尾附加用于 SQL 注入的任何额外 sql,还是对属性的某个方法调用,因为方法调用也可用于更改 SQL 的预期行为。

接下来,你问:

order 子句 LOWER(name) ASC 不包含任何用户输入

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

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

评论

0赞 53c 8/31/2023
这个答案的第一部分与SQL注入有什么关系?如果真的是,我会理解.你是说注射可以通过吗?MyModel.order('LOWER(name) ASC')MyModel.order(order_sql)name
1赞 Zia Ul Rehman Mughal 9/1/2023
@53c Rails 无法知道自定义字符串的来源,它不知道这个字符串是由受信任的程序员编程的,还是用户输入的,这就是为什么它对它们都是一样的。