Is this code snippet from Rails vulnerable to sqli ? if so what is the payload - ruby-on-rails

Am used to working with PHP and Prepared statement, now when i was looking at the following piece of code from rails ( since i a new to rails and Not sure about the syntax and stuff ) , i was wondering if the code is prone to SQLI injection
Code snippet (controller ) , param q is the value from a search box :
def index
query = %w(% %).join params[:q].to_s.gsub('%', '\\%').gsub('_', '\\_')
#posts = Post.where("name LIKE ? OR body LIKE ?", query, query).order(params[:order])
end
Thanks

What you have is intended to be safe. If it is not, then it's a bug in Rails.
.where accepts conditions in several formats. One is a raw string. If you build that string yourself, all bets are off and you are vulnerable.
As some recent documentation says:
Note that building your own string from user input may expose your
application to injection attacks if not done properly. As an
alternative, it is recommended to use one of the following methods.
In other words, ALL of the "following" (every other supported way) ways of doing things, are OK.
So if you are doing .where with anything other than string parameter, you should be fine.

As long as you don't interpolate within your where clause it should be safe. There are some good examples of SQL injection code here

Related

Is ActiveRecord's “order” method passed with hash vulnerable to SQL injection?

Adding to the same question from (HERE), I am planning to use hash instead of string as parameter. Say,
User.order(params[:column].to_sym => params[:direction].to_sym)
Where params[:column] and params[:direction] are passed from the page for sorting the table (Reference). I even added .to_sym to both parameters just so that it will be forced into a symbol instead of string just to be safe (although I am not sure if this is even necessary)
Now, I would just like to know if this approach is safe.
P.S. tried ransack gem, however I couldn't do nested queries. So I wrote my own customizable one.
I think this is at least still open for a Denail of Service attack.
http://brakemanscanner.org/docs/warning_types/denial_of_service/index.html
The reference is from a nice gem called brakeman which finds vunerable things in a rails application.
In general I would advise you to use #dmcnally's approach from the other issue you posted.
Here an example of what I did in my own projects:
SORT = { newest: { created_at: :desc },
cheapest: { price: :asc },
most_expensive: { price: :desc }
}.stringify_keys
And then use SORT[param[:sort]] to get the sort order. You can also do this by using two seperate hashes for direction and column like you supposed. If you use brakeman you will be able to have a little but of safety since it finds most things like that.
Symbols don't protect you from SQL injection, query parametrization protects you from SQL injection - and this only on the value side, not on the column name side. The thing to take from the other article is "not safe to use interpolated strings in column name when calling .order", not "not safe to use strings when calling .order",
your example defines ordering using a hash - that hash gets translated into a parametrized SQL query in AR, so it is safe as long as you sanitize the column name. One liberal way to do this is to:
raise "Unknown column name #{params[:column]}" unless YourModel.column_names.include?(params[:column])
PS What .to_sym does in your example is that it enables a third party to define a new symbol on the ruby vm. Symbols are never garbage collected so the attacker can send many different values so that your ruby processes hog the system memory - thus opening you to a ddos attack. The cast in the end does nothing because if you look here you'll notice your value gets cast into string anyway :)

What is the best possible way to avoid the sql injection?

I am using ruby 1.8.7 and rails 2.3.2
The following code is prone to sql injection
params[:id] = "1) OR 1=1--"
User.delete_all("id = #{params[:id]}")
My question is by doing the following will be the best solution to avoid sql injection or not. If not then what is the best way to do so?
User.delete_all("id = #{params[:id].to_i}")
What about:
User.where(id: params[:id]).delete_all
Ok sorry for Rails 2.x its:
User.delete_all(["id = ?", params[:id]])
Check doc
Btw, be sure you want to use delete_all instead of destroy_all, the former doesn't trigger callbacks.
You can use this also
User.delete(params[:id])
The other answers answer this well for Rails and it'll work fine if you follow their suggestions. In a more generic setting when you have to handle this yourself you can typically use a regular expression to extract a value that's in an expected format. This is really simple with an integer id. Think of it like this:
if params[:id] =~ /(\d+)/
safe_id = $1.to_i
# do something with safe_id now
end
That gets a little more complicated when you're handling strings and arbitrary data. If you have to handle such data then you can use the quoting methods available for the database adapters. In Rails this is ultimately rolled into a consistent interface:
safe_string = ActiveRecord::Base.connection.quote(unsafe_string)
For most database systems this will handle single quotes and backslashes in a special manner.
If you're outside of Rails you will have to use the quoting methods specific to your database adapter, but usage is quite similar.
The takeaway:
If your data has a particular format, enforce the format with a regular expression
Otherwise, use your database adapter's quoting function to make the data "safe" for use in a query
Rails will handle most of this for you if you properly use the various methods and "conditions"
Use the rails methods to pass your where options. You can always hardcode them, as in the example that you give, but the usual way would be something like:
User.where(:id => params[:id]).delete_all
User.where("id = ?", params[:id]).delete_all
User.where("id = :id", :id => params[:id]).delete_all
They are well tested and in case a new vulnerability is detected, an update will fix the problem and your code will not need to be changed.
By the way, if you just want to delete 1 record based on its id, what I would do is:
User.find(params[:id]).destroy

Is there a good Rails plugin to expose a query interface to Angular?

Angular.js allows me to query a server resource cleanly from the client and pass up parameters which I'd like restrict how I query the server resource.
However in order to actually process those parameters on the server I need to write a load of code to safely consume such a query and then translate it into a Rails query.
Is there any nice gem that easily allows you to expose a rich way to query the database via REST in a safe and controlled way?
I dont think so and I dont think it would be a great idea.
A quick way would be (Rails 4):
# very important!
white_list = [:age, :country, :gender]
query = User.all
params.slice(*white_list).each do |key, value|
query = query.where(key => value)
end
An ambiguity would be when you want to call an existing scope instead of a basic where, but there is no obvious way to abstract it, so you should write some code.

Complex search screens in Rails 3

I need to implement some search functionality within a Rails application. Most of the stuff I have found is generally aimed at simple plain-text search. I am trying to implement something much more specific. The sort of functionality I am looking to create is this (from a C application):
http://andyc.ac/query.gif
The form just submits the data entered by the user. So I need to translate strings like "3..7" into SQL conditions for the where method e.g.
TestLine.where( "test_int >= ? and test_int <= ?", MinInt, MaxInt )
It seems like this is something that already exists somewhere. The exact format expected is not too important, as the users are not shared between the Rails and C applications. How would this be done?
FWIW the specific functionality you describe is actually supported directly. Well.. almost. From the docs:
A range may be used in the hash to use the SQL BETWEEN operator:
Student.where(:grade => 9..12)
Of course then it's a matter of translating the user's string input to a Range, which isn't very complex, e.g.:
def str_to_range str
str =~ /(\d+)\.\.(\d+)/
Range.new *$~.captures.map(&:to_i)
end
It would probably make the most sense in a scope on your model. (Of course a shortcut would be to simply eval '9..12' but evaling input from the end user is a really, really bad idea.)
Give a look at thinking sphinx(http://freelancing-god.github.com/ts/en/). It might make your task a lot easier. You can search in that:
http://freelancing-god.github.com/ts/en/searching.html#basic

Ruby on Rails build query in pieces

There was a very similar question before but i still struggle.
Is it possible to build a query up in stages?
Let's say I have a search form with many text and select fields that may be chained with and/or or which could be blank.
So the sql statement should consist of several parts that are connected individually for each search.
I tried to create strings for every option and put them to a symbol? (i mean #options) and put that in the where clause (e.g. Product.where(#options) ). That works somehow but i have got troubles with this part: 'params[:query]' when it's in quotes. Either my sql statement says 'select products from products where (name like params[:query]') or if i try #{params[:query]} it says: select products from products (where 'name' like ''.)
So how can i chain different parts of a query?
I looking forward to your answers!
Never, ever, ever embed raw strings in your SQL. This is extremely bad form. You should always use the escaping mechanism provided by Rails or something equivalent to avoid ending up in serious trouble. Inserting content from params is very dangerous and should never be done as it only takes this to nuke your app: { :query => '\"-- DROP TABLE users;' }
Generally you use the helper methods provided by ActiveRecord to build up your query in stages:
scope = Product
if (params[:query].present?)
scope = scope.where([ 'name LIKE ?', "%#{params[:query]}%" ])
end
if (params[:example].present?)
scope = scope.where(:example => true)
end
#products = scope.all
You can build it up in stages like this, modifying the scope in-place each time, and then execute the final call to retrieve it. Generally that's when you use your paginator to split up the results.
It's okay to put pretty much anything in your options because it should be escaped by the time it hits the SQL phase, much as anything on the HTML side is escaped for you as well.
Don't confuse instance variables like #options with a symbol like :query. The two are very different things. Instance variables have the benefit of propagating to your view automatically, so they are often used extensively in controllers. Views should avoid modifying them whenever possible as a matter of style.

Resources