14

我正在尝试将字符串传递给 .order 方法,例如

Item.order(orderBy)

我想知道 orderBy 是否默认被清理,如果没有,清理它的最佳方法是什么。

4

5 回答 5

21

订单未经过消毒。这个查询实际上会删除用户表:

Post.order("title; drop table users;")

如果有任何方式可能被用户输入污染,您需要orderBy在运行查询之前检查变量。orderBy像这样的东西可以工作:

items = Item.scoped
if Item.column_names.include?(orderBy)
  items = items.order(orderBy)
end
于 2013-02-15T15:45:48.147 回答
11

它们的清理方式与带有 的.where子句不同?,但您可以使用#sanitize_sql_for_order

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

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

http://api.rubyonrails.org/classes/ActiveRecord/Sanitization/ClassMethods.html#method-i-sanitize_sql_for_order

于 2016-08-02T14:20:20.717 回答
8

只是为了更新 Rails 5+,在撰写本文时,将数组传递给orderwill(尝试)清理右侧输入:

Item.order(['?', "'; DROP TABLE items;--"])
#=> SELECT * FROM items ORDER BY '''; DROP TABLE items;--'

这将在 Rails 5.1 中触发关于“危险查询方法”的弃用警告,该警告在 Rails 6 中将被禁止。如果您知道左侧输入是安全的,将其包装在Arel.sql调用中将使警告静音,并且可能仍然有效在 Rails 6 中。

Item.order([Arel.sql('?'), "'; DROP TABLE items;--"])
#=> SELECT * FROM items ORDER BY '''; DROP TABLE items;--'

需要注意的是,左侧的不安全 SQL 将不加修改地发送到数据库。谨慎行事!

如果您知道输入将成为模型的属性,则可以将参数作为哈希传递:

Item.order(column_name => sort_direction)

在这种形式中,如果列名对模型无效或排序方向无效,ActiveRecord 会报错。

于 2018-10-11T21:43:13.210 回答
3

我使用如下内容:

@scoped = @scoped.order Entity.send(:sanitize_sql, "#{@c} #{@d}")

其中 Entity 是模型类。

于 2015-02-24T15:18:41.350 回答
1

ActiveRecord::Relation用扩展sanitized_order

在Dylan 的带领下,我决定扩展以ActiveRecord::Relation添加一个可链接的方法,该方法将自动清理order传递给它的参数。

这是你如何称呼它的:

Item.sanitized_order( params[:order_by], params[:order_direction] )

以下是您如何扩展ActiveRecord::Relation以添加它:

配置/初始化程序/sanitized_order.rb

class ActiveRecord::Relation

  # This will sanitize the column and direction of the order. 
  # Should always be used when taking these params from GET.
  #
  def sanitized_order( column, direction = nil )
    direction ||= "ASC"

    raise "Column value of #{column} not permitted."       unless self.klass.column_names.include?( column.to_s ) 
    raise "Direction value of #{direction} not permitted." unless [ "ASC", "DESC" ].include?( direction.upcase ) 

    self.order( "#{column} #{direction}" )
  end

end

它主要做两件事:

  1. 它确保column参数klassActiveRecord::Relation.

    在我们上面的示例中,它将确保params[:order_by]Item' 列之一。

  2. 它确保方向值是“ASC”或“DESC”。

它可能会更进一步,但我发现在接受用户的排序参数时,易用性和 DRYness 在实践中非常有用。

于 2018-04-09T03:52:55.857 回答