我该如何避免sql注入?

时间:2012-12-17 20:48:33

标签: mysql ruby-on-rails

我有一个问题:

@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 个答案:

答案 0 :(得分: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}% %'
    ]
)

虽然是#39;如果你在字符串中有%,我不确定它的表现。

答案 1 :(得分:1)

您可以在嵌入之前或之后使用input字符串上的sanitize方法。这基本上是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)。

答案 2 :(得分: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)

答案 3 :(得分:1)

你也可以试试squeel gem:

https://github.com/ernie/squeel

Rian Bates,在他的RailsCasts中,对squeel做了很好的介绍:

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