如何在 order rails 查询中修复 sql 注入

Posted

技术标签:

【中文标题】如何在 order rails 查询中修复 sql 注入【英文标题】:How to fix sql injection in order rails query 【发布时间】:2021-06-21 00:06:12 【问题描述】:

我是 ruby​​ 新手,关注 this 博客修复 sql 注入错误,但我的查询出错。

原始查询:

class Car < ActiveRecord::Base
  ...
  has_one :Driver, lambda 
     where(status: PASSENGER_STATUS, connected_number: [phone, mobile])
    .order("FIELD (`classDummy`.`status`, #PASSENGER_STATUS.join(', ')")
  , class_name: :classDummy

而 PASSENGER_STATUS 是(在其他类中)

PASSENGER_STATUS = [
  'employed','temporary'
  ].freeze

我做了 SQL INJECTION 修复

  order("FIELD (`classDummy`.`status`, ? )", PASSENGER_STATUS.join(', '))

但这会在执行查询时抛出异常。

我得到的例外:

ActiveRecord::StatementInvalid: Mysql2::Error: 你的 SQL 语法有错误;检查与您的 MySQL 对应的手册 在 '?,

附近使用正确语法的服务器版本

【问题讨论】:

什么异常? @Geoffroy :添加了有问题的异常。 【参考方案1】:

正如 Geoffroy 已经指出的那样,在您的具体示例中,没有 SQL 注入风险,因为输入数据在您的控制之下。

不过,您可以在 Rails 文档中找到sanitize_sql_for_order。文档中的示例与您的用例完全匹配:

sanitize_sql_for_order(condition)

接受一个数组或 SQL 条件字符串,并将它们清理为 ORDER 子句的有效 SQL 片段。

sanitize_sql_for_order(["field(id, ?)", [1,3,2]])
# => "field(id, 1,3,2)"

sanitize_sql_for_order("id ASC")
# => "id ASC"

使用这种方法,您可以像这样编写您的关联:

has_one :Driver, lambda 
     where(status: PASSENGER_STATUS, connected_number: [phone, mobile])
       .order(sanitize_sql_for_order(["FIELD(`classDummy`.`status`, ?)", PASSENGER_STATUS])
, class_name: :classDummy

【讨论】:

【参考方案2】:

您阅读的博客是关于处理用户输入的,在这种情况下,防止 sql 注入非常重要。

在:

order("FIELD (`classDummy`.`status`, #PASSENGER_STATUS.join(', '))")

您是 SQL 查询中的注入代码,但它是您控制的代码,并且确切地知道它是什么,因此不存在 SQL 注入的风险。

现在关于您的问题,order 在生成查询时不会替换参数?,它根本不像where 那样工作。

换句话说:使用您之前使用的代码,它工作得非常好,并且不受 SQL 注入的影响(只要您控制 PASSENGER_STATUS 是什么)

查看日志以查看发送到服务器的 SQL 查询,您会更好地了解发生了什么

【讨论】:

感谢您的回答。我会尝试更改我的查询。

以上是关于如何在 order rails 查询中修复 sql 注入的主要内容,如果未能解决你的问题,请参考以下文章

如何显示在 Rails 控制台中运行的 SQL 查询?

如何将sql中的查询转换为rails中的查询

Rails/SQL:如何在特定 id 上查找最频繁的列值

如何在 Ruby on Rails 中查看给定 ActiveRecord 查询将生成的 SQL

Rails Group、Order 和 Limit 在一张表 Active Records 中

如何在 PHP 8 中修复这个动态 SQL 查询功能?