2

我有一个查询:

@results = the_db.where('name LIKE ?', '%#{input}%').paginate(
    :page => params[:page], 
    :per_page => 50, 
    :group => "name", 
    :order => [
        "CASE WHEN name like '#{input}%' THEN 0 
        WHEN name like '% %#{input}% %' THEN 1
            END, name"
    ]
)

问题是这很容易被注射。(订单条款)我该如何解决这个问题?是否有可能以某种方式清理用户的输入以否定任何攻击?

4

4 回答 4

1

使用参数化查询。

@results = the_db.where('name LIKE ?', "%#{input}%").paginate(
    :page => params[:page], 
    :per_page => 50, 
    :group => "name", 
    :order => [
        "CASE WHEN name like ? THEN 0 
        WHEN name like ? THEN 1
            END, name",
            '#{input}%',
            '% %#{input}% %'
    ]
)

虽然我不确定如果你%在字符串中它会如何表现。

于 2012-12-17T20:59:50.947 回答
1

您可以在嵌入之前或之后sanitize在字符串上使用该方法。input这基本上就是 Rails 参数化为您所做的。

请注意,清理将添加前导和尾随单引号',如果需要,您可以使用以下命令将其删除:

sanitize(something)[1..-2] 

在您的示例中,您可以执行以下操作:

:order => [
    "CASE WHEN name like #{sanitize "#{input}%")} THEN 0 
    WHEN name like #{sanitize "% %#{input}% %")} THEN 1
        END, name"
]

请注意,您将需要sanitize在类方法或范围内调用,或者使用可以访问它的命名空间(例如ModelName.sanitizeActiveRecord::Base.sanitize)。

于 2012-12-17T21:07:32.110 回答
1

您可以使用该sanitize_sql_array方法。不幸的是,它是一个私有方法,所以你必须用send.

query = <<-QUERY
CASE WHEN name like ? THEN 0 
     WHEN name like ? THEN 1
     END, name
QUERY

sanitized_order = ActiveRecord::Base.send :sanitize_sql_array, [query, "'#{input}%'", "'% %#{input}% %'"]

@results = the_db.where('name LIKE ?', '%#{input}%').paginate(
:page => params[:page], 
:per_page => 50, 
:group => "name", 
:order => sanitized_order)
于 2012-12-17T21:12:18.470 回答
1

您还可以试用 squeel gem:

https://github.com/ernie/squeel

Rian Bates 在他的 RailsCasts 中很好地介绍了 squeel:

http://railscasts.com/episodes/354-squeel?view=asciicast

于 2012-12-17T22:25:42.477 回答