Ruby on Rails build query in pieces - ruby-on-rails

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.

Related

Rails SQL Injection: How vulnerable is this code?

I'm trying to understand SQL Injection. It seems like people can get pretty creative. Which gets me wondering about my search-based rails webapp I'm making.
Suppose I just fed user-entered information directly into the "where" statement of my SQL query. How much damage could be done to my database by allowing this?
def self.search(search)
if search
includes(:hobbies, :addresses).where(search)
else
self.all
end
So basically, whatever the user types into the search bar on the home page gets fed straight into that 'where' statement.
An example of a valid 'search' would be:
"hobby LIKE ? OR (gender LIKE ? AND hobby LIKE ?)", "golf", "male", "polo"
Does the fact that it's limited to the context of a 'where' statement provide any sort of defense? Could they still somehow perform delete or create operations?
EDIT:
When I look at this tutorial, I don't see a straightforward way to perform a deletion or creation action out of the where clause. If my database contains no information that I'm not willing to display from a valid search result, and there's no such thing as user accounts or admin privileges, what's really the danger here?
I took this from another post here: Best way to go about sanitizing user input in rails
TL;DR
Regarding user input and queries: Make sure to always use the active record query methods (such as .where), and avoid passing parameters using string interpolation; pass them as hash parameter values, or as parameterized statements.
Regarding rendering potentially unsafe user-generated html / javascript content: As of Rails 3, html/javascript text is automatically properly escaped so that it appears as plain text on the page, rather than interpreted as html/javascript, so you don't need to explicitly sanitize (or use <%= h(potentially_unsafe_user_generated_content)%>
If I understand you correctly, you don't need to worry about sanitizing data in this manner, as long as you use the active record query methods correctly. For example:
Lets say our parameter map looks like this, as a result of a malicious user inputting the following string into the user_name field:
:user_name => "(select user_name from users limit 1)"
The bad way (don't do this):
Users.where("user_name = #{params[:id}") # string interpolation is bad here
The resulting query would look like:
SELECT users.* FROM users WHERE (user_name = (select user_name from users limit 1))
Direct string interpolation in this manner will place the literal contents of the parameter value with key :user_name into the query without sanitization. As you probably know, the malicious user's input is treated as plain 'ol SQL, and the danger is pretty clear.
The good way (Do this):
Users.where(id: params[:id]) # hash parameters
OR
Users.where("id = ?", params[:id]) # parameterized statement
The resulting query would look like:
SELECT users.* FROM users WHERE user_name = '(select user_name from users limit 1)'
So as you can see, Rails in fact sanitizes it for you, so long as you pass the parameter in as a hash, or method parameter (depending on which query method you're using).
The case for sanitization of data on creating new model records doesn't really apply, as the new or create methods are expecting a hash of values. Even if you attempt to inject unsafe SQL code into the hash, the values of the hash are treated as plain strings, for example:
User.create(:user_name=>"bobby tables); drop table users;")
Results in the query:
INSERT INTO users (user_name) VALUES ('bobby tables); drop table users;')
So, same situation as above.
I hope that helps. Let me know if I've missed or misunderstood anything.
Edit Regarding escaping html and javascript, the short version is that ERB "escapes" your string content for you so that it is treated as plain text. You can have it treated like html if you really want, by doing your_string_content.html_safe.
However, simply doing something like <%= your_string_content %> is perfectly safe. The content is treated as a string on the page. In fact, if you examine the DOM using Chrome Developer Tools or Firebug, you should in fact see quotes around that string.

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

Iterating through array of Models in rails

Yet another ruby question but this is a bunch of questions in one. I'm really starting to like rails but there are some questions that I'd just like to ask straight out.
Right now, I'm implementing a queue in sqlite. I already have a scaffold setup with this working OK. The purpose is for a web crawler to read through the array and determine which links he should crawl next.
The architecture in the program is 2 controllers. one for Job and one for crawler. The Jobs has the standard Crud interface supplied by scaffold. Where I'm falling down is I'm still trying to understand how these things communicate with eachother.
The Job is formatted as a url:string and depth:decimal. The table is already populated with about 4 objects.
#sitesToCrawl = Job.all
#sitesToCrawl.each {|x|puts Job.url}
I have a bunch of questions about the above.
At the moment, this was supposed to display all the jobs and I foolishly thought it would display plain text but its actually a hexidecimal pointer to the object itself. What Im trying to do is iterate through the #sitesToCrawl and put out each Jobs url.
Questions start here:
1: I know ruby is dynamically typed. Will #sitesToCrawl become an array like i want it to be with each slot containing a job.
2: #sitesToCrawl.each is pretty straighforward and I'm assuming its an iterator.
is X the name od the method or what is the purpose of the symbol or string between |*|
3: Puts and print are more or less the same yes? if i say #x = puts 3 then would x be 3?
4: Job.url. Can objects be referenced this way or should I be using
##sitesToCrawl = db.execute("SELECT url FROM jobs;")
where db is a new database
As Rubish Gupta pointed out, in your block, you should do x.url, otherwise you're trying to access the url method on the class Job, not on instances of Job. In other words, in blocks, the items in the pipes are the arguments of the block, and each will iterate through your array, passing in one item at a time to your block. Check out the doc here.
Just to extend this idea, each on Hashes (associative arrays, maps, whatever you know them as) will pass two variables to your block: a key and a value, like this:
a_hash.each {|key_var, val_var| puts "#{key_var} is associated with #{val_var}"}
Also, it's been a bit since I've done plain ActiveRecord models, but you might look into doing
#sitesToCrawl = Job.all.to_a
since Job.all is a lazy finder in that it's building a query in potentia: you've essentially built a query string saying SELECT * FROM jobs, but it might not be executed until you try to access the items. each might do that, I can't remember off the top of my head, but if you're using a debugger to look at it, I know you need to_a to get it to run the query.
You should absolutely be using job_instance.url - that's the beauty of ActiveRecord, it makes database access easy, provided everything gets set up right :)
Finally, puts and print are almost the same - the difference is that puts "string" is essentialy print "sting"; STDOUT.flush - it flushes at the end of the statement.

Is this Rails 3 search vulnerable to SQL injection?

Suppose I've got a search box on a page in a Rails 3 app where you can search for a client by business name or city. In my controller's index method I do this:
if params[:search]
#clients = Client.where("clients.business_name LIKE :business_name OR clients.city = :city", :business_name => "%#{params[:search]}%", :city => params[:search])
Those hash values get substituted into the SQL and surrounded in quotes. If my input into the search box includes quotes or other dangerous characters, I'll see them being escaped in the development log, like:
...WHERE (clients.business_name LIKE '%Something\' DROP TABLE Foo%'...
Or
...WHERE... OR clients.city = 'Something OR 1=1')
So, since the OR 1=1 is inside the quotes Rails adds, it just produces no match for the city name, and since the quote in the DROP TABLE attempt is escaped, it also produces no match for the business name.
This isn't using actual prepared statements, where the query is sent to the database first without the search values filled in, then subsequently, the search values are sent to the database to fill in. I thought that was the safest approach, but Rails doesn't do it; I think this is because it's not available in all databases and implementations vary.
Is this open to SQL injection in some way? I don't see it, but again, it's not using prepared statements, so I wonder. If there's a vulnerability, how could I do this more safely?
No, there's not a SQL injection vulnerability here. ActiveRecord will call connection.quote on the values of the hash that you passed in as the second parameter to where, so you are safe.
The only potential SQL injection point I could think of would be if there were some undiscovered bug in connection.quote, which is pretty unlikely.

Sanitizing data at active record

I want to sanitize the data coming from my form in ActiveRecord. Especially the apostrophe before its actually included into the SQL query. I want it to be something raghu'\s if raghu's is been inputed. I have already tried using:
sanitize_sql_array
sanitize_sql_for_assignment
sanitize_sql_for_conditions
sanitize_sql_hash_for_assignment
sanitize_sql_hash_for_conditions
But none of these seem to escape the apostrophe there by failing my SQL query.
Rails will handle a lot of the santizing for you if you use the following format for performing finds. It'll run the necessary sub methods to ensure that nothing potentially destructive is inserted into the database. Not sure about the single inverted comma, but it's worth a shot.
Model.find(:all, :condition => ["text_value = ?", params[:form_input])
You might want to have a look at this thread - Strip & Sanitize BEFORE saving data from the Ruby Forum - I haven't tried any of the solutions mentioned but it might get you going in the right direction

Resources