Rails 4 Quick Look: Strong Parameters

Tweet


Rails always comes up with some and creative new features, and Rails 4 is no exception. One of the new features in Rails 4 is Strong Parameters.
The basic idea behind Strong Parameters is to move mass-assignment protection out of the model and into the controller where it belongs.

Just so we’re all on the same page, let’s talk about Mass-Assignment before focusing on strong parameters.

Mass-Assignment: Assigning attributes of a model in a hash

Let’s take an simple example.

Assume we have a User model with name, email, and admin. Admin is a boolean attribute used to indicate if the user has administrative rights.

The Rails way of creating a user looks like:

and updating:

This is often done by sending parameters through a form and creating/updating the object in controller. This way we don’t need to set value of each attribute.

Problem with Mass-Assignment: Security vulnerability

Mass-assignment saves us the need to assign values to each attribute of the model, but it can create problems. Since we aren’t restricting which attributes can be set nor are we checking the valus of these attributes, a malicious hacker could assign any value to any attribute. In our example, he could set the value of admin true, making himself a super user.

Here is what the url might look like

http://www.example.com/user/signup?user[name]=ow3ned&user[admin]=1 

or through form using browser console

After clicking on the button you will see

This way the user can exploit the security vulnerability.

As you might guess, this is bad, and it gets worse. This is not limited to only one model, if we have model relationships like has_many,has_one or has_many :through

When an account record is created, rooms can also be created through mass-assignment(params[:account]). In other words, referenced tables can also become target of attackers

There is a live example of this kind of security vulnerability that happened on Github. Because of mass-assignment, a user passed his ssh-key through the public key update form to add himself into the Rails repository and created a commit.

You can read more about that vulnerability here.

How to Avoid Mass-assignment Attack

Now that we know what mass-assignment is, we can address the issue.

First of all, don’t panic, Rails has solutions for this.
There are two ways:

1. Rails has a class method attr_protected that is used to specify attributes that can not be part of mass-assigntment.

Now the admin value is not accessible for mass-assignment. Attackers can not update this value in url or through a form.

2. The other way to protect all models in your app from mass-assignment is to set config.active_record.whitelist_attributes to true in config/application.rb

Now all model’s attributes are not accessible for mass-assignment. But if we want some attributes to be accessible for mass-assignment, we can use the attr_accessible method

attr_accessible is just opposite of attr_protected. When an attribute passed to the attr_accessible method, it becomes available for mass-assignment

In Rails 3.2.3 config.active_record.whitelist_attributes is true by default and in all models attr_accessible method is used for whitelisting the attributes.

Rails enabled this feature just after when hackers breach the security of Github, as I mentioned earlier.

Strong Parameters: New way to handle mass-assignment protection

Mass-assignment Protection is going to be done in a new way in Rails 4. As previously mentioned, mass-assignment protection moves into the controller where it belongs.

Today with the Strong Parameters gem made by DHH, you can just call “PERMIT” .

To explore it more lets write some code.
Say we have a book_store app, with a model called Book. The Book model has name, author and public(boolean) attributes. We have user authentication based on role (admin,user).

Mass-Assignment Protection at Model Level

In the Book model :

Every user can create and update book and make them public from User Interface.

If we want to restrict users that are not admins from updating the public attribute, then we need to do something like:

In BooksController we need to do like :

Now only admin can update public field through form. Now, we add a new role called reporting_user who can only update name.

We have to add some more conditions in controller also like

As you can see we all are handling user access control on the basis of user role that’s related more to controller instead of model. We know the controller handles the flow between user and application, authentication and authorization, which is why mass-assignment protection should be handled in the controller instead of model.

Let’s look at Strong Parameters now, first in Rails 3.

Mass-Assignment Protection at Controller Level: Strong Parameter Gem

In Rails 3.2.7 attributes are whitelisted by default, so first we need to remove (or set it to ‘false’) the following code in config/application.rb

Next add add the gem in Gemfile

and run bundle to activate strong_parameters.

Add the following line to the Book model:

This will raise an ActiveModel::ForbiddenAttributes exception because it’s using mass assignment

Now in our controller we handle mass-assignment calling a permit :

Also, you can specialize this private method with per-user checking of permissible attributes:
params[:book].permit(:name,:author,:public)

You can do :

If a user other than admin attempts to add/update the public field value, it won’t raise any error but justignore this update.

According to the docs, it supports nested attributes. For example, if a book has many chapters, then in the controller we can call permit like:

Strong Parameters will be part of Rails 4.
If you make a sample app with Rails 4 and generate a scaffold user with name and email attributes, it will generate a user_params private method :

There is lots of discussion going on around this issue. You can check the commits here

Wrap Up

I think we’ve just about covered most things about mass-assignment and strong parameters.

With Strong Parameters :

  • You can keep your model code clean
  • You can handle authorization and access of parameters in the controller where it belongs

If you want to learn more about mass-assignment and strong_parameters:

And if you enjoyed reading this post, you’ll love Learnable; the place to learn fresh skills and techniques from the masters. Members get instant access to all of SitePoint’s ebooks and interactive online courses, like Jump Start Rails.

Comments on this article are closed. Have a question about Ruby on Rails? Why not ask it on our forums?

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Karan

    Wow !! Thanks for the detailed blog Rashmi ..

  • Harald

    Thanks for the heads up. Looks like a nice feature. Sounds like getting started with the strong_parameters gem right away is a good idea.

  • http://gouravtiwari.blogspot.com Gourav

    Very nicely written and explained in detail. Well done!

    I just observed a typo near;

    params[:user] = {:name => ‘Foo’,:email => ‘foo@example.com’}
    @user = User.new(params[:blog]) # should be params[:user]

    • http://raysrashmi.com Rashmi Yadav

      Thanks for reading this. I fixed that typo mistake

  • http://agrawalarun.com Arun Agrawal

    This is awesome post. Good work. Keep it up!

  • Tomasz

    Strong parameters gem have very poor documentation and wiki is empty. Your post is far more descriptive. Thanks!

  • Satty Bhens

    Great article. Helps a ton!

  • Sean

    This’s a great article!!
    Thanks for your effort!!

  • Alan Brown

    Clear, concise and complete. Thanks!

  • Jayawanth

    Nice write up. I am unable to follow towards the end where you introduce require method

  • http://www.marnen.org Marnen Laibow-Koser

    The `as:` stuff looks great, but isn’t the `require` and `permit` technique something of a step backwards? Now you need to filter in every controller action, instead of once in the model. Or am I missing something?