Are find_by_[dynamic] Activerecord methods safe for unsanitized input? - ruby

I am using ActiveRecord and Sinatra (probably irrelevant context). ActiveRecord has a dynamic finder method find_by_[column]
I would like to pass a raw parameter string from HTTP directly into one of these methods. I'm pretty sure that ActiveRecord will sanitize the string I pass in. Right? Here's some example code to show what I want to do:
post '/login' do
user = User.find_by_username(params[:username])
...
end
Is it problematic to pass unsanitized http parameters into this kind of ActiveRecord method?
More generally, how should one go about figuring out which ActiveRecord methods sanitize their inputs? I keep reading this site and getting scared! http://rails-sqli.org/

Yes, they are safe. Because the dynamic finders are simply translated into the normal hash form. Find the implementation at github
Note that the new syntax (since version 4) is: find_by(username: params[:username])

To be sure if the user exists you can try something like:
if User.exists? :username => params[:username]
user = User.find_by_username(params[:username])
end
This greatly reduces the chances of SQLi.

Related

Assistance in understanding the following methods: request.query_string

I've tried searching both the site and the Ruby docs, however, I am unable to find a clear answer to exactly what the above is doing.
From what I understand, 'request' and 'query_string' are two separate methods, however I'm really unsure what they do - the latter in particular.
Any help would be super appreciated!
Thank you.
In Rails, the #request method available in controllers and views returns a ActionDispatch::Request instance. The Request object allows access to data from the HTTP Request.
The #query_string method, defined in Rack::Request::Helpers, returns the query string from the request url. This is the part in the url following the "?" which specifies url encoded data in the format key=value&other_key=other_value.
Note:
ActionDispatch::Request is a Rails class that behaves similarly to a Rack::Request, including Rack::Request::Env and Rack::Request::Helpers in the current version of Rails v 5.0. In previous versions ActionDispatch::Request inherited directly from Rack::Request.
Read more:
https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/http/request.rb
http://api.rubyonrails.org/classes/ActionDispatch/Request.html
https://github.com/rack/rack/blob/master/lib/rack/request.rb

Rails 4: using both strong params and "normal" params

I'm kind of new to Rails 4. Right now, I'm using both strong params and "normal" params. By normal params I mean the params[:key] which is not permitted.
For example:
Strong params:
def person_params
params.require(:person).permit(:name, :age)
end
And I use both person_params[:name] and params[:key]. Is this going to be problems in the future? what should I do.
You should always use Strong Parameters.
Strong params was created to avoid the issue of Mass Assignment.
This means that if you directly use your params hash, you run into the risk of someone sending a request with parameters they aren't supposed to use and successfully overwrite them in your models.
This means that, for example, someone could gain admin privileges on your site from their "settings" page by maliciously crafting a request that modifies a hypothetical admin attributes in your User model.
Using strong params gives you the guarantee that only the parameters explicitly allowed by you will pass through to the model, so no attacker should be able to bend your application's restrictions.

How can request params be validated to ensure they include required params and don’t include unsupported params?

This is particularly in the context of a REST API built with Ruby and Sinatra.
It's easy enough to manually check to make sure that the required params are not nil. And it's easy to iterate through a flat params hash to see if it's allowed in a whitelist.
However, when the params hash also include hashes it becomes more difficult.
One way of handling this I've thought of is converting the params hash to JSON and using a library to validate it against a JSON schema.
I have come across the sinatra-param gem but I haven't had a chance to see if it can validate sub-hashes or check for unsupported params.
Edit: Another possible way, that might make more sense is passing params directly to the model (I'm using DataMapper) and using its validation and errors instead of rewriting validations.
If each of your routes are going to take the same 4 params (IE :one, :two, :three, :four), you could set up a before filter, store an array of those four params as an instance variable in the before (which is accessible to all routes) and use a sexy little method from class Enumerable called all?:
before do
#base_params = [params[:one], params[:two], params[:three], params[:four]]
unless #base_params.all?
redirect '/error_route'
end
end
Enumerable#all? will return true only if all values in your 'collection' are not false or nil. Documentation can be found here for Ruby 1.9
Additionally if you find that you have different sets of params, you can create a hash instead of just an array of #base_params where they keys are the string value of request.request_method:
before do
#base_params = {"GET" => [params[:one], params[:two], params[:three], params[:four]],
"POST" => [params[:five], params[:six], params[:seven]],
"PUT" => [params[:one], params[:five], params[:six]]}
unless #base_params[request.request_method].all?
redirect '/error_route'
end
end

Local variables in a block that are not passed as parameters [duplicate]

This question already has answers here:
Rails params explained?
(5 answers)
Closed 9 years ago.
I'm trying to understand how to make a variable available to a block that is not passed to the block as a parameter.
For example, how does Sinatra make params hash available?
get '/hello/:name' do
howAmIAccessingThis = params[:name]
end
Where is params coming from? This:
get '/hello/:name' do |params|
#hisName = params[:name]
end
might make sense because params is declared as a block argument, but that's not how it works. Looking through the source I cannot find how the params hash is getting passed to the block without it being a block parameter.
If it is not a local variable or a block variable, then it is a method. I don't know about Sinatra, but there must be a method params defined somewhere.
Using Parameters
Parameters in Sinatra are like everything else--simple and straightforward.
#!/usr/bin/env ruby
require 'rubygems'
require 'sinatra'
get '/hello/:name' do
"Hello #{params[:name]}!"
end
Once you've made this change, you'll need to restart the Sinatra application. Kill it with Ctrl-C and run it again. (There's a way around this, but we'll look at that in a future article.) Now, the parameters are straightforward. We've made an action called /hello/:name. This syntax is imitating what the URLs will look like, so go to http://localhost:4567/hello/Your Name to see it in action.
The /hello portion matches that portion of the URL from the request you made, and :name will absorb any other text you give it and put it in the params hash under the key :name. Parameters are just that easy. There is of course much more you can do with these, including regexp-based parameters, but this is all you'll need in almost every case.
Reference: http://ruby.about.com/od/sinatra/a/sinatra2.htm
EDIT
params values can come from the query string of a GET request, or the form data of a POST request, but there's also a third place they can come from: The path of the URL.
As you might know, Rails uses something called routes to direct requests to their corresponding controller actions. These routes may contain segments that are extracted from the URL and put into params. For example, if you have a route like this:
match 'products/:id', ...
Then a request to a URL like http://example.com/products/42 will set params[:id] to 42
So, whenever an URL GET, POST or Path contains such pattern then params hash is automatically constructed by rails.
Also check the Parameters section(Section 4) here

Passing Sinatra models and validation

As mentioned on another similar thread I started recently, I am porting an ASP MVC application to Sinatra, partly for learning, partly for production purposes.
Currently my ASP MVC application has no views, it just exposes models as Xml/Json etc and accepts them in the same way. So in the scenario of someone sending a model to the server, it would auto bind the object, perform validation then return validation errors if there are any, if not carry on with the relevant actions.
Now in Sinatra it is a bit more barebones that ASP MVC which is a great thing as I have more choice on how to do these parts, however I dont have a clue what gems/libraries functionality is available for doing this.
My ideal scenario would be I have my pure html/js front end posting a model as json and then have it turned into an actual model where I can validate it (through Sinatra or other framework) then make a decision based on the validation results.
Try taking a look at this gem:
json
Then what you should be able to do is pass in the attributes for an object you would like to create as a hash of attributes converted to a json object:
{:attribute1 => "value1", :attribute2 => "value2"}.to_json
And on your Sinatra app, catch them and build the object from those attributes, and you can use Sinatra to validate as well:
def '/create_object' do
content_type :json
obj = Object.new(JSON.parse(params[:object]))
if obj.save
obj.to_json
else
error 400, user.errors.to_json
end
end
Sounds like an ordinary case for an ORM. So you could for example use DataMapper. With that in your hands, you can simply send a form via HTTP to a specific route and do something like:
post '/create' do
#post = Post.new(params[:your_form])
if #post.save
erb :a_template
else
erb :your_form
end
end
Where params[:your_form] is a hash containing the contents of your form. No JSON needed at all. If the saving process fails (for validation reason or whatever), the model object #post will have errors, which you could process in a different view (:your_form for example).
Best Regards
Tobias

Resources