NoSQL Injection with a simple find_by in RoR - ruby-on-rails

I am new to RoR and I have a basic question.
A colleague told me that the following code can cause a NoSQL Injection:
User.find_by(username: param[:username])
I know that I am not supposed to read directly from param but I still think that the code cannot generate any NoSQL injections. Am I wrong?

Your colleague is wrong, and should produce a working exploit if he believes this is true.
Providing a hash of key/value pairs to Rail's find_by or where methods is the intended, secure, and correct way of using those methods. The keys and values are always made safe before being used in a query.
There are certain problems that Rails will not protect you from, for example, the value of params[:username] could be a gigabyte of text, a File object, a nested hash of key/value pairs, etc. but this isn't an "injection" per se. Any special characters that could cause the meaning of the query to be changed will have no effect.

Related

Is nosql injection possible for Ruby on Rails with Mongoid?

I'm trying to investigate if nosql injection is possible on Ruby on Rails with mongo and mongoid gems.
I did Mongodb's requests using Mongo::Client collections and models with Mongoid::Document inclusion.
I tried to pass some command characters like ' " \ ; { }, but is was sanitaized. Passing GET search?title[$ne]=foo was traited like {"title"=>"{\"$ne\"=>\"foo\"}"}, so it don't seems like any problem here.
Is any nosql injection possible if I use ordinary methods of this technology stack?
Common operations including queries and inserts/updates in Mongoid sanitize their inputs, thus most times one does not need to worry about "nosql injection".
However, there are methods that pass commands directly to the database, and in those cases it is important to carefully consider whether unsanitized user input can end up as a database command. For example, if Post is a Mongoid model, one can run the following command to create an infinite loop in a MongoDB server:
Post.all.map_reduce('function(){while(true);}','function(){}').out(inline:1).count
Another example is Database#command method provided by the driver to run arbitrary database commands: http://api.mongodb.com/ruby/current/Mongo/Database.html#command-instance_method. If an application places user input into parameters given to this method, this creates potential for "nosql injection".
Note also that it is not necessary to pass an unexpected command to the database - sometimes unexpected data is sufficient. See, for example, https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS. Assuming the Post model has a body field, passing an arbitrary regular expression from the user could be problematic:
# This might take a while
Post.where('body' => {'$regex' => '((a|a?|a*)*)*$'}).count
This is from the mongdodb docs
As a client program assembles a query in MongoDB, it builds a BSON
object, not a string. Thus traditional SQL injection attacks are not a
problem. More details and some nuances are covered below.
MongoDB represents queries as BSON objects. Typically client libraries
provide a convenient, injection free, process to build these objects.
Consider the following C++ example:
https://docs.mongodb.com/manual/faq/fundamentals/#how-does-mongodb-address-sql-or-query-injection
Possible, and easily overlooked.
In fact, you are pretty close.
Untrust sources are not just from GET parameters.
Mongoid won't help you with anything; in your example, what prevents the succeeded exploitation is the fact that, in RoR, you can't pass a Hash as a GET parameter.
An unsanitized parameter can come from JSON, like this one for example.
posts = PrivatePost.where({ owner_id: json_params[:owner_id] }).each.to_a
Where json_params[:owner_id] could contains { '$ne': 'the owner' },
which can leak posts to someone else.
Or mess with the operation scope via POST-based API:
Post.where({ _id: json_params[:id] }).delete_all

With Rails 5, what is the most efficient way to generate and use a Basecamp-style "hash_id" (instead of sequential row id's) for each new record?

What I'm going for is URL's very similar to Basecamp's:
https://3.basecamp.com/4000818/buckets/7452203/message_boards/1039416768
I have already achieved this functionality by following this guide, but I am unsatisfied with the process of needing to run potentially millions of .exists? lookups to find an open number and fear this will very quickly hamper performance of my app.
def set_hash_id
hash_id = nil
loop do
hash_id = SecureRandom.urlsafe_base64(9).gsub(/-|_/,('a'..'z').to_a[rand(26)])
break unless self.class.name.constantize.where(:hash_id => hash_id).exists?
end
self.hash_id = hash_id
end
I find it hard to believe that Basecamp is relying on something so inefficient on every record save and I'm looking to find out how they do it or to find a setup that will look the same but without the overhead of the linked tutorial.
I'd appreciate any input on methods to generate a non-sequential record ID. I am not interested in UUID's as I can't stand the non-pleasing URL's they generate. Also, they must be integers. Basically, exactly like the Basecamp URL but without the overhead of the exists? checks. Is it possible they are doing some kind of combination of numbers with an encoded timestamp or something to ensure there is no collisions? I have explored the hashids.org method but this does not generate integer-only hashes.
I am using Postgres as my database, in case this is helpful.
Efficiency-wise I think you should be fine. GitLab also uses something similar for unique token generation.
There's another issue though that's worth considering:
Your method does not guarantee to generate a unique key, as the operation is not atomic (neither is GitLab's). Between checking for uniqueness and writing the record to the database the same key could have been generated.
You have at least 2 options to handle this. Both solution should also be more efficient (which is your main concern).
Catch the DB's unique key constrain violation on save
def save
begin
self.hash_id = generate_hash_id
super
rescue ActiveRecord::RecordNotUnique => e
# 1. you may need to check the message for the specific constraint
# 2. you may need to implement an abort condition to prevent infinite retries
retry
end
end
You could can also do this in an ActiveRecord callback.
Have the DB generate the key
An alternative solution would be to have your database generate the unique key on create. A function like the one described in this blogpost A Better ID Generator For PostgreSQL may serve your purpose better.
This solution has the advantage that your application code does not need to be concerned about generating or catching collisions. The drawback is though that this solution is DB specific.

ActiveRecord accessor dot(.) vs bracket([])

With Active Record, we can access a value like
method access
user = User.find(1)
user.name #=> 'John'
or
hash access
user[:name] #=> 'John'
I just wonder when to use which, or is there any best practice out there?
Personally I'd prefer method access because I feel that is more like ruby way. However when I see code by others, I face the hash access.
Rails convention is to use ActiveRecord::AttributeMethods::Read#read_attribute (dot notation), rather than its alias ActiveRecord::AttributeMethods#[], which:
Returns the value of the attribute identified by attr_name after it
has been typecast (for example, “2004-12-12” in a date column is cast
to a date object, like Date.new(2004, 12, 12)). It raises
ActiveModel::MissingAttributeError if the identified attribute is
missing.
I would strongly advise against using bracket notation as it breaks the inheritance hierarchy of method calls and makes refactoring harder.
If my model has an attribute name, and I decide I want to enhance the name every time someone reads it, a very idiomatic way to do that would be:
def name
"Awesome #{super}!"
end
Any place in my app that uses the method version would work fine, any place that uses the [] notation would return raw database data. I could overwrite the [] but then I would need special conditions checking for specific attributes. The whole thing would be a nightmare.
Another scenario, let's say I had an attribute that used to be stored in the database, but after a while decide that it should be computed on the fly, and end up dropping the database column. With the method version all I would need to do is add methods to my model. With the [] notation the process would be much much harder.
Also [] provides an insignificant performance improvement so though it looks like it's "closer" to the raw data it really isn't.

Is it safe to call params at slim template in rails?

I just want to know if it is safe to call params like params[:id] which come from the request parameter in url (eg. /?id=<script>console.log(1)</script>) at slim tempalate for rails like h3 = params[:id] because of security reason.
Is the params automatically escaped or sanitized?
Thanks for your help.
This really depends on context, but in general I would say rendering raw params directly in a view is an anti-pattern. Params are really the concern of the controller. I can't think of a case where you'd want to render a raw parameter in a view without some preliminary processing, validation, or sanitization.
Params (along with any other value) would be HTML sanitized in the view, although, remember, it's likely that users could provide any value they want here, so it's worth asking yourself what vulnerabilities or boundary conditions this may cause.
Finally, while this isn't an absolute rule, I'm strongly of the opinion that primary IDs should remain a concern of the database. In some cases it may be risky to expose them to the user or outside world. The reason is that you're leaking information about your database (e.g. how many records there are) if the primary key is auto-incrementing, which it usually is. In such cases it might be worth obscuring or hashing the primary key.

If we cache params into a local var in an action, will it help or its the same?

So we run a code quality tool called reek once in a while as part of our project. The tool basically looks for code smells and reports them. Here, we observed that we get "Duplication" smell every time we try to access a key in params more than once (As if we are making a method-call twice with same parameters or we are duplicating an if condition etc). However, params is just a Hash, right? Other hashes don't get duplication smell when their keys are accessed more than once.
Why is this so? What are params exactly? Does it make sense to cache params in a local variable then use them? Will it help or its the same? Or is there something wrong with the tool? Help!
With the current version it's best to run Reek only on your app/models folder, because it raises false positives against views and controllers.
params is a kind of DTO (data transfer object) close to the system boundary, and so its characteristics should be different than regular code. But Reek doesn't know that (yet). I plan to improve Reek in the near future so that it plays better with Rails. For now though, your best bet is to restrict it to looking at app/models (and maybe app/helpers and lib).
params is a method call that does a #params ||= #request.params
It might be that it thinks params is a complicated method, so it wants you to try and cache it in a variable, but, dont think that would be worth it especially since it is memoized (based on my rack_process.rb from Rails 2.2)
params[:foo] is a method-call to Hash#[], so reek is correct. I'm not familiar with reek, so I can't tell why other Hash accesses don't get counted the same. Hash#[] should be fast enough that you don't need to store it in a local variable unless you're in a very performance critical part of your code.
The only difference between the params Hash and a regular Hash is that it uses with_indifferent_access, meaning you can access any key with a String or a Symbol.
I believe every time you call params, there is an initialization step which generates method calls, i suppose you can try creating a params and checking number of calls.
this could be blind guess. :-)

Resources