Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is ActiveRecord's "order" method vulnerable to SQL injection?

I know it's not safe to use interpolated strings when calling .where.

e.g. this:

Client.where("orders_count = #{params[:orders]}")

should be rewritten as:

Client.where("orders_count = ?", params[:orders])

Is it safe to use interpolated strings when calling .order? If not, how should the following be rewritten?

Client.order("#{some_value_1}, #{some_value_2}")

like image 418
Mike Avatar asked Jul 25 '13 13:07

Mike


People also ask

What is SQL injection Rails?

And that's what we call a SQL injection attack: an ability to modify the SQL query that an application is executing against the database. If you want to learn more about the attack itself, read our post, What is SQL Injection? Let's dive in to SQL injections, specifically in the case of the Rails framework.

What is Arel SQL Rails?

Arel is a powerful SQL AST manager that lets us appropriately combine selection statements for simple to very complicated queries. However, reader be cautioned – Arel is still a private API provided by Rails. Meaning that future versions of Rails could be subject to changes in Arel.


2 Answers

Yes, ActiveRecord's “order” method is vulnerable to SQL injection.

No, it is not safe to use interpolated strings when calling .order.

The above answers to my question have been confirmed by Aaron Patterson, who pointed me to http://rails-sqli.org/#order . From that page:

Taking advantage of SQL injection in ORDER BY clauses is tricky, but a CASE statement can be used to test other fields, switching the sort column for true or false. While it can take many queries, an attacker can determine the value of the field.

Therefore it's important to manually check anything going to order is safe; perhaps by using methods similar to @dmcnally's suggestions.

Thanks all.

like image 158
Mike Avatar answered Nov 07 '22 02:11

Mike


Short answer is you need to sanitize your inputs.

If the strings you are planning to interpolate come from an untrusted source (e.g. web browser) then you need to first map them to trusted values. You could do this via a hash:

# Mappings from known values to SQL
order_mappings = {
  'first_name_asc'  => 'first_name ASC',
  'first_name_desc' => 'first_name DESC',
  'last_name_asc'   => 'last_name ASC',
  'last_name_desc'  => 'last_name DESC',
}

# Ordering options passed in as an array from some source:
order_options = ['last_name_asc', 'first_name_asc']

# Map them to the correct SQL:
order = order_options.map{|o| order_mappings[o] }.compact.join(', ')
Client.order(order)
like image 24
dmcnally Avatar answered Nov 07 '22 02:11

dmcnally