我正在尝试将字符串传递给.order方法,例如
Item.order(orderBy)
我想知道orderBy是否会默认清理,如果没有,那么最好的清理方法是什么。
答案 0 :(得分:16)
订单没有消毒。此查询实际上将删除Users表:
Post.order("title; drop table users;")
如果orderBy
有任何方式可能会被用户输入污染,那么您需要在运行查询之前检查orderBy
变量。这样的事情可以奏效:
items = Item.scoped
if Item.column_names.include?(orderBy)
items = items.order(orderBy)
end
答案 1 :(得分:6)
它们的清理方式与使用.where
的{{1}}子句相同,但您可以使用?
:
#sanitize_sql_for_order
答案 2 :(得分:2)
我使用以下内容:
@scoped = @scoped.order Entity.send(:sanitize_sql, "#{@c} #{@d}")
其中实体是模型类。
答案 3 :(得分:0)
ActiveRecord::Relation
扩展sanitized_order
。考虑Dylan's lead我决定扩展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
它主要做两件事:
它确保column
参数是klass
的基础ActiveRecord::Relation
的列名称。
在上面的示例中,它会确保params[:order_by]
是Item
列之一。
确保方向值为“ASC”或“DESC”。
可以采取进一步措施,但我发现在接受用户排序参数时,易用性和干燥性在实践中非常有用。
答案 4 :(得分:0)
仅针对Rails 5+进行更新,在撰写本文时,将数组传递到order
将(试图)清除右侧输入:
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将会进行投诉。