Was mass assignment really the culprit in Homakov's GitHub hack? - ruby-on-rails

Many commentators (e.g. ZDNet) have suggested that the weakness in GitHub's case was that the model Homakov discovered was vulnerable had mass assignment enabled for its attributes.
However, I think the problem was not this, but was rather a failure to use a before_filter (or suchlike) in the controller to ensure that any given row in the table he updated could only be updated by an admin or by the user with the ID listed in that row. If such a filter had been in place in the controller, then the table would have been secured from attack even if the model's attributes were mass assignable.
Am I correct?

Yes, I think you're right.
In such situations, you can also use authorization gem, for example: cancan, declarative authorization, heimdallr...
The problem is not that you can use. The problem is how to help do not forget to use it in certain situations. For example cancan have the following method: check_authorization It helps to check authorization for all actions.
About that says Homyakov. Add the protected attribute would be the easiest way. Maybe vulnerability has been discovered just because solution to restrict the authorization was different. In some situations, adding of protected attributes leads to a loss of flexibility in your api.

As far as I understand this issue has nothing to do with before_filters checking for admins.
An attribute existed, in the exemple you cite the user_id on the public_keys model, that was not supposed to be exposed to mass assignment.
The before_filter can work as another "layer" of security as .slice can be also used to ensure that you only get the attributes you supposed to get can also work.
On a last note: I think admin != god, meaning, I find no use to a Github admin having rights to perform the action Homakov was able to perform exploiting this issue.

Related

Rails custom validation involving current_user

I have been developing a rails app in which we allow different users to submit different values for an attribute of a model.
For example all users can submit values greater than 10 while administrators are allowed to submit one-digit values as well.
As we know models do not have access to the current_user helper, therefore you can not write a custom validator with ease.
What's the best practice when implementing such a feature?
This is a perfect use case for validation contexts. You define the contexts in your model, but then your controller specifies which context to use.
Here is a nice article by Justin Weiss about them—although he doesn't mention that they solve problems not solved well any other way, per-user validation rules being the perfect example, since your model doesn't have access to the current user, and your controller isn't designed to specify validation rules:
https://www.justinweiss.com/articles/a-lightweight-way-to-handle-different-validation-situations/
It's always advised to keep logic like current_user outside your model.
But given your requirement,
Well, as our controller knows current_user then it should be the controller that tells your model about it.
So in your model add an attr_accessor for current_user
and in your controller do something like
#model_obj.current_user = current_user
Now all this being said. I'd propose using an alternative to model validation. Because in real what you are trying to do is giving users permissions based on their role. You'd be better of using a gem like Pundit for it.
This is probably a case where you enforce the validation in the controller. Strictly speaking this is not about model validation, but about user authorisation. Pundit is a nice gem for authorisation or you can roll your own.

Ruby on rails. How safe is an admin attribute for user model?

I can't find any definitive answers to this.
I have a user model with devise, and I have added an 'admin' attribute that is a boolean, which defaults to false. Currently I have to go to the console and manually change the attribute to true to give a user this admin status.
My question is, how secure is this? Is there any way for someone to change the status of their own user without accessing the server (Currently my computer)?
Could safety be compromised once I put the site into production? The admin attribute is not a permitted parameter on sign in, sign up or update.
I am asking as I want to add a personal dashboard for myself to view, edit or delete anything I might need to when the site goes into production.
If you use strong params then the risk is only if you allow setting this attribute from any action outside of admin panel.
To be extra safe you can use attr_readonly so you can only set this attribute when object is created.
Considering Devise, safety is the last thing that could go wrong, unless either one of Rails or Devise is broken, which is unlikely.
You have taken sufficient steps like not allowing the admin parameter, which should be enough for pretty much every situation.
Several Rails applications, including GitHub and Shopify have been doing this (possibly without Devise, but that's not a concern) without security issues. I myself use Devise and admin flags and can vouch that it is safe enough.
Any reason you are not using something like RoleModel? It will allow you to expand to other roles in the future in a much more manageable way than adding an attribute to User for each role.
Either way... unless you provide a way for them to update that field, it should be secure. If you want to ensure that there's no way a non-admin could update that field, you could always add something like this to UsersController#update:
params[:user].delete(:admin) unless current_user.admin?

Role based security mechanism for attributes in Rails

I'm looking for a plugin that provides a role based authorization mechanism for securing read/write access to attributes. I'm picturing something along the lines of declarative_authorization for white listing attributes of model objects. I've spent some time looking around but have come up short, does anyone know of anything?
EDIT: I'm using declarative_authorization to control which users have access to what actions in the controller, but I need something similar that provides access control to the attributes of each model object. I'm trying to prevent information leakage through the web API or users from crafting malicious posts. I can do this through the mass_assignment_authorizer but I was hoping some plugin did this already.
CanCan Branch 2.0
https://github.com/ryanb/cancan/tree/2.0
Edit:
The continuation of CanCan is called CanCanCan.
See https://github.com/bryanrite/cancancan
What about creating a model / controller pair for each controller, and then allowing each role only to access methods in its controller(s)? Then you can make a before_filter in each controller that makes sure each user has permission to use methods in that controller.

Restful model ownership validations

I know there are role based authorization gems/plugins for rails to determine if a user can do things based on which role their in. However, is there a best-practice approach to hiding actions from users based on ownership? ie: the show/edit/destroy methods for a user should only be available if they're being performed on the currently logged in user id. Hopefully that makes sense, but I've written some methods to protect against non-owners accessing methods and its become a bit bloated and ugly.
Look at cancan's implementation.
I can recommend on restful_authentication( https://github.com/technoweenie/restful-authentication ). quick tutorial http://railscasts.com/episodes/67-restful-authentication

What is the best way to securely add administrative access to my rails website?

I think the answer is an admin login and then check if the user has an admin flag, but I also thought of some other related questions.
Is it better to have an admin flag (attr_protected) in the same user table as non admins? or should i have an admin users table?
Should I create a separate rails application for the admin users? This might be overkill since they will both have to access the same datbase (not to mention it might be a huge pain to set up).
Any other suggestions? Right now I just need to secure a page or two so I even looked into HTTP basic or digest authentication as a temporary measure (the protected content is actually not THAT private/important). But... I don't know how to implement HTTP auth for specific actions, I have only seen how to implement it to prevent directory access.
Any direction and discussion would be great. I am sure other Stack Overflow users will benefit from this discussion.
Thanks!
Ryan Bates has a great three part series of Railscasts on this topic which should give you some food for thought:
Part 1: Where Administration Goes
Part 2: Restricting Access
Part 3: Super Simple Authentication
There are also three Railscasts on different authentication techniques:
RESTful Authentication
HTTP Basic Authentication
Authlogic
I'm using restful_authentication plugin for this purpose. And it is very simple to restrict access to any controller or any method. On example in controller add this function:
private
def authorized?
user.admin?
end
or
private
def authorized?
user.admin? if update? || create?
end
I defined admin? method in my User model. I also created update? and create? methods that check which action was called. In restful_authentication authorized? method is always run when accessing controller.
I would put everything in one application and in one table (don't create users and admin table). You can secure admin flag in your users controller by allowing to set this value only for existing admin users.
I think it depends on the type of administration.
If the view your administrators will have of the site is the same as a normal user's, but with additional privileges, I would go with an admin flag. (Or, as your needs expand, a full-fledged roles table.) This is a situation where everybody sees the same stuff, but administrators have access to various actions (delete? edit? ban? etc.) that normal users do not.
If the view your administrators need is wildly different than the normal site, I would recommend a completely separate Rails app that accesses the same database. For example, if your "administrators" are really help desk employees that are going to answer phone calls or deal with billing questions, they may have completely different views of the database (and perhaps ways to edit the data) that aren't available in the regular application.
The disadvantage to having multiple sites is that it is possible to have models (validations, associations, etc.) get out of sync. The disadvantage to having a single site is that you may end up inserting all sorts of ugly "if-admin" code in previously easy-to-understand portions of your site. Which problem is easier to handle depends on your requirements.

Resources