Security impact of using constantize - ruby-on-rails

I'm currently reviewing some Rails controller. That controller takes user input and based on that user input a new object is created like so:
clazz = params[:type].classify.constantize
clazz.new(some_method_which_returns_filtered_params)
I'm concerned with the security of this approach. Are there classes in Ruby which the 'new' method could be used with malicious intent?
For example it might be possible to flood the program with new Symbols causing a denial of service (see http://brakemanscanner.org/docs/warning_types/denial_of_service/).

I'd recommend limiting the values that this code will accept for params[:type], before executing it. Eg with an if block like
if %w(foos bars bazzes).include?(params[:type])
clazz = params[:type].classify.constantize
clazz.new(some_method_which_returns_filtered_params)
end
I don't think DOS attacks are a specific problem with doing classify.constantize here: if someone spams your server with requests then that's going to DOS attack you whatever you do in the actual controller.
Preventing DOS attacks is hard. Securing web apps is a massive subject, but in particular you seem to be talking about the area of "sanitizing parameters" here. Have a look at
http://guides.rubyonrails.org/security.html
I can't resist linking to this classic XKCD strip: http://xkcd.com/327/

Related

How would it be written using REST?

I am making a browser game, it's completely AJAX-based, so I am trying to create a proper RESTful API.
So, I have a User model (basically, User has weapon, health and action points).
So I have a users resource. Now, I want to implement user attacks.
Scenario: user with id = 1 attacks user with id = 2.
What I would do is like this:
Send the following info (with POST-request):
target_id (well, it's stored in ApplicationController from session)
attacker_id
weapon_id (weapon attacker uses to attack his target)
to /users/attacker_id/attack/
Validate if user has enough action points and health for attack, if target is not dead yet. If these conditions fail - do nothing, if they succeed - decrease attackers action points and ammo, decrease target HP. All of this is done in model method called attack for attacker.
Is it a proper way in general or if there is a better, Rails way?
Thank you!
REST really makes the most sense when what you're doing are resource-based CRUD interactions. You're not really doing that in this case--you can sort of conceptually force it to conform, but I think you'd end up adding unnecessary and unintuitive complexity.
I'd say you just don't use REST. Just have an attack action that takes the params and does the rest.

Why not refer to the session hash in the Model layer?

This question has been repeatedly asked and answered with one-line assertions, such as "because it is an obvious violation of MVC." Frankly, I just don't get it. Indeed, it feels to me that putting session inside the controller merely an artifact that ApplicationController faces the network layer via a rack call, rather than an MVC mandate. Let me explain my problem.
Rolling an authentication from scratch, I found myself agonizing and spiking all over the place for lack of ability to articulate simple tests (session isn't available to the testing framework either). My authentication scheme, as almost all I have seen in rails, wanted to use the session hash as a persistence layer to retain the id for the User model of the "current user." Doesn't that feel FAR MORE like a model than a controller artifact?
The code smells are obvious whenever you look at the "typical" sessions controller (this one from Ryan Bates excellent screencasts). Desperate to shovel this concept in with rest, we see unhealthy language such as:
def create
user = User.find_by_email(params[:session][:email])
if user && user.authenticate(params[:session][:password])
session[:user_id] = user.id
redirect_to root_url, notice: "Logged in!"
else
flash.now.alert = "Email or password is invalid"
render "new"
end
end
To me, this is a code smell, an obviously overlogicked controller that is screaming for refactoring! But we can't. Why? Oh yes, because it is a violation of MVC to put references to the session, used as a persistence lawyer into the model. WTF? Doesn't it say something to you that we seem to want to CALL THIS REST RESOURCE /sessions?
To see why this is just plain screwy, look at your login views -- hand-coded html, or use of the "_tags" API? If we had an ActiveModel model to do this code, then the create code could look like the usual scaffolding, or possibly even reduced to the "respond_with" one-liner.
def create
recognition = Recognition.new(params[:user])
if recognition.save
redirect_to root_url, :notice => "Thank you for signing up!"
else
render "new"
end
end
Then, take a look at the hand-coded html for all of those views! If Recognition was a model, persisted by session (or some other means that should not be the responsibility of the controller layer anyway), then you could simple use form builder or simple_form to generate the forms. Of course, we could simply pass the session hash to a "new_login" class method of Recognition, say Recognition.on(session).new(params[:recognition]), but that seems uglier than it has to be. Perhaps it is inherent, as we will want to use a current_user reference later in the application layer, perhaps Recognition.on(session).current_user similar to the way one might use a singleton pattern?
Just try to build your authentication package with strict BDD, and honestly tell me you haven't spiked this portion of it? If we had a Recognition model, this entire thing would be reduced to a simple set of unit tests without hackery. Now, instead we have the "sole" use case for integration testing, magic invasions of ActiveController modules and hacks to make speedy any acceptance testing of the logged_in_as predicate.
I think the entire point of ActiveModel was to facilitate this kind of rethinking and refactoring. Not all models use "the" database. Why not persist to the "session?"
I have been using devise and its kin for too long, burying these smells with the "dont mess with the gem" excuse I don't have to look at them. No longer! I think I am going to reject the zealots from now on. Sorry, to me, session is a persistence layer that should be manipulated in the Model layer of MVC. I posit, but am not sure, that the reason it lives in controllerland has more to do with the ugly or elegant fact that controllers are rack objects than any theoretical MVC magic.
So once again, is there a more elegant way to access the session layer than to have logic in the controller for that?
Maybe it's just me, but I don't sniff the code smell in that controller. I guess it depends on what you think should go into controllers versus models.
I think people take the "skinny controllers" idea to an unhealthy extreme at times. Yes, you want everything that can be in a model to be on the model: but controllers exist to change models based on application state, and you should allow them to fulfill that design goal. Having every controller be something like:
def create
Creator.create(params) # Pass all params to the creator model, which will automatically detect what object you're trying to create, make it, and then render the appropriate view
end
def show
Shower.show(params) # Find the model object and the view based on the params and render them together
end
Defies the idea of separation of concerns and creates nightmarish problems for people trying to update and maintain your code. Controllers should call model objects and even methods on those models to create and persist application state, and models should be agnostic to the state of the application. If you couple them together too tightly you'll end up with view and controller code in your models, at which point it becomes very difficult to determine what's where in your application.
If this is what you want and you think it serves your goals, then go for it -- but your code will be more difficult to maintain and will be hard for other people to understand. MVC exists because it's a sensible way to separate concerns and makes your code less surprising for other people.
All of this said, the session model you're proposing is actually a pretty good idea... and hence, it already exists. ;) The authlogic framework has a Sessions model: when logging in using authlogic, you create a new UserSession with the params object. UserSessions live in the models folder and exist solely to abstract away the nitty gritty of authentication into a controller-aware model class, so if that's what you're looking for, it's already been done for you! Go check out the authlogic github repository for documentation and usage examples.
I would still shy away from passing any kind of controller state into a real ActiveRecord model though. Allow your controllers to manipulate models and render the results of that manipulation as HTML -- it's what they're there for!

Prevent modification ("hacking") of hidden fields in form in rails3?

So lets say I have a form for submitting a new post.
The form has a hidden field which specify's the category_id. We are also on the show view for that very category.
What I'm worried about, is that someone using something like firebug, might just edit the category id in the code, and then submit the form - creating a post for a different category.
Obviously my form is more complicated and a different scenario - but the idea is the same. I also cannot define the category in the post's create controller, as the category will be different on each show view...
Any solutions?
EDIT:
Here is a better question - is it possible to grab the Category id in the create controller for the post, if its not in a hidden field?
Does your site have the concept of permissions / access control lists on the categories themselves? If the user would have access to the other category, then I'd say there's no worry here since there's nothing stopping them from going to that other category and doing the same.
If your categories are restricted in some manner, then I'd suggest nesting your Post under a category (nested resource routes) and do a before_filter to ensure you're granted access to the appropriate category.
config/routes.rb
resources :categories do
resources :posts
end
app/controllers/posts_controller
before_filter :ensure_category_access
def create
#post = #category.posts.new(params[:post])
...
end
private
def ensure_category_access
#category = Category.find(params[:category_id])
# do whatever you need to do. if you don't have to validate access, then I'm not sure I'd worry about this.
# If the user wants to change their category in their post instead of
# going to the other category and posting there, I don't think I see a concern?
end
URL would look like
GET
/categories/1/posts/new
POST
/categories/1/posts
pst is right- never trust the user. Double-check the value sent via the view in your controller and, if it does't match something valid, kick the user out (auto-logout) and send the admin an email. You may also want to lock the user's account if it keeps happening.
Never, ever trust the user, of course ;-)
Now, that being said, it is possible to with a very high degree of confidence rely on hidden fields for temporal storage/staging (although this can generally also be handled entirely on the server with the session as well): ASP.NET follows this model and it has proven to be very secure against tampering if used correctly -- so what's the secret?
Hash validation aka MAC (Message Authentication Code). The ASP.NET MAC and usage is discussed briefly this article. In short the MAC is a hash of the form data (built using a server -- and perhaps session -- secret key) which is embedded in the form as a hidden field. When the form submission occurs this MAC is re-calculated from the data and then compared with the original MAC. Because the secrets are known only to the server it is not (realistically) possible for a client to generate a valid MAC from the data itself.
However, I do not use RoR or know what modules, if any, may implement security like this. I do hope that someone can provide more insight (in their own answer ;-) if such solutions exist, because it is a very powerful construct and easily allows safe per-form data association and validation.
Happy coding.

rails 3, is there a way to keep skinny controller when controller uses lots of session info?

I like a nice skinny controller as much as the next guy.
But the app I'm working on talks extensively to a remote system via JSON, and the session variables are used extensively... each little interaction is a separate hit to one of dozens of controller methods, and rails' built-in session tracking keeps track of all the state.
Consequently, the controller has dozens of methods, one for each "interaction" and those methods extensively read (and sometimes write) the session.
It's my understanding that if you're accessing the session in your model methods you're doing something horribly "wrong" ... but having 100+ lines of code PER controller-method for dozens of controller methods seems "wrong" too.
Given that scenario, what IS the best tradeoff between fat controllers vs models that access the session?
I recently came across a similar problem. I was writing and application that depended heavily on a remote API that accepted/returned JSON. Subsequently, I had very few models in my application, and my controllers were quite lengthly.
I ended up writing a custom parser module in lib/ and made calls to the Module (which handled a lot of the logic that would normally exist in the controller)
Consider the following:
module RemoteParser
def get_user(user_id)
result = ActiveSupport::JSON.parse(NetHttp.get('http://www.example.com/'))
session[:received_user] = true
end
end
Now your controllers can be skinny again:
class SomeController < ApplicationController
def index
#user = RemoteParser::get_user(params[:id])
end
end
I'd just like to add that this is an incredibly contrived example of such uses. If you provide additional information about what your requesting, etc, I can help you further.

Staying RESTful while performing AJAX server-side validations?

My Rails application has a number of forms. When Joe uses my app, I want each form to provide him with immediate visual feedback as to the validity of his input for each field. One field checks the format of his email address - pretty simple. But another allows him to associate the current resource with a number of other resources, and complex business rules apply. If the form is incomplete or invalid, I want to prevent Joe from moving forward by, for example, disabling the 'submit' button.
I could duplicate the validations that appear in my Rails code by writing JavaScript that does the validation in the browser as well. But this smells bad - any time business rules change, I'll need to update them in two places with two different languages and two sets of tests.
Or I could add a single method to the controller for the resource called 'validate'. It would accept form data in an AJAX request, and return a response that could then be used inside Joe's form to provide real-time validation feedback. Unlike the 'create' action, the 'validate' action would not change the state of the server. The only purpose of 'validate' would be to provide a validation response.
The dilemma is that I don't like adding actions to RESTful controllers in Rails. But I like even less the idea of duplicating validation code in two different contexts.
I noticed this SO question, which touches on this subject. But I'm not interested in a plugin or piece of technology. Nor do I consider this question necessarily Rails-specific. I'm more interested in how best to handle this kind of problem in general in a Web application.
I also notice this SO question, which doesn't include the constraint of maintaining a RESTful architecture.
Given the need to dynamically validate form data with complex business rules in a Web application, and the desirability of maintaining a REST-like server architecture, what is the cleanest, most maintainable way to accomplish both at the same time?
I see no problem in creating a validator "processing resource" that can accept an entity and ensure that it passes all validation rules.
You could do this either with a global validator
POST /validator
where the validator will have to identify the passed representation and perform the appropriate rules, or you could create subresources,
POST/foo/validator
As long as these urls are discovered via hypermedia and the complete representation to validate is passed as a body of the request, I see no REST constraints being violated.
I hope I understood correctly, but you could send the javascript requests to the same create action. For example:
def create
#data = DataObject.new(params[:data])
if request.xhr?
response = #data.valid? ? { :success => true } : { :errors => #data.errors }
render :json => response
return
end
# #data.save etc..
end
I'm actually using something like this in a multistep wizard (one page form, with hidden css sections).
You are right not to duplicate validation logic on client (javascript) and server side). But adding validation resources also adds maintenance effort and costs server network calls. I like to do basic validation on client side (better user experience) and for data consistency on server side also.
Why don't you attach your model with validation metadata and then the forms + javascript for validation gets generated. On the final submit you also do a final validation on server side based on the model.
I am sure some generic validation logic is possible with Ruby. I guess also some existing validation frameworks could be reused.

Resources