STRONG PARAMETERS IN RAILS 4

STRONG PARAMETERS IN RAILS 4

1. What is Strong Parameters?

Strong Parameters is one of new features in rails 4. The basic idea behind Strong Parameters is to move mass-assignment protection out of the model and into the controller where it belongs. So, what is mass-assignment?

2. What is mass-assignment?

Mass-assignment using to assigning attributes of a modle in 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:

params[:user] = {:name => ‘Foo’,:email => ‘[email protected]‘}
@user = User.new(params[:user])

And updating:

 @user = User.update_attributes(params[:user])

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.

3. Problem with Mass-Assignment: Security vulnerabilit

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 user data updated 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

class Account < ActiveRecord::Base
   has_many :rooms

   accepts_nested_attributes_for :rooms

 end

class Room < ActiveRecord::Base

   belongs_to :account

 end

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.

4. How to Avoid Mass-assignment Attack

Rails has solutions for this.

There are two ways:

4.1 Rails has a class method attr_protected that is used to specify attributes that can not be part of mass-assigntment.
 class User < ActiveRecord::Base

    attr_protected :admin

 end

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

** 4.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

 config.active_record.whitelist_attributes = true

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.

class User < ActiveRecord::Base

    attr_accessible :name

end

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.

Note: in other way, you can make some code thi handle role for access attribute in a modle.

4.3 Using Strong Parameters 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.

Let’s look at Strong Parameters now (Strong Parameters set default in Rails 4):

Note: if you using 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

 config.active_record.whitelist_attributes = true

Next add add the gem in Gemfile

gem ‘strong_parameters’

and run bundle to activate strong_parameters

Add the following line to the Book model:

class Book < ActiveRecord::Base
    include ActiveModel::ForbiddenAttributesProtection
end

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

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

class BooksController < ApplicationController
  def create
    @book = Book.new(book_params)
    respond_to do |format|
      if @book.save
        format.html { redirect_to @book, notice : ‘Book was successfully created.’ }
      else
        format.html { render action : “new” }
      end
    end
  end
  def update
    @book = Book.find(params[:id])
    respond_to do |format|
      if @book.update_attributes(book_params)
        format.html { redirect_to @book, notice : ‘Book was successfully updated.’ }
      else
        format.html { render action : “edit” }
      end
    end
  end
  private
  def book_params
    if current_user && current_user.admin?
      params[:book].permit(:name, :author, :public)
    else
      params[:book].permit(:name, :author)
    end
  end
end

Also, you can specialize this private method with per-user checking of permissible attributes:

params[:book].permit(:name,:author,:public)

You can do :

params.require(:book).permit(:name,:author,:public)

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:

params[:book].permit(:name,:author,:chapters_attributes => [:number_of_pages])

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 :

def user_params

  params.require(:user).permit(:name, :email)

end

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

4.4 Nested Parameters

You can also use permit on nested parameters, like:

 params.permit(:name, {:emails => []}, :friends => [ :name, { :family => [ :name ], :hobbies => [] }])

This declaration whitelists the name, emails and friends attributes. It is expected that emails will be an array of permitted scalar values and that friends will be an array of resources with specific attributes : they should have a name attribute (any permitted scalar values allowed), a hobbies attribute as an array of permitted scalar values, and a family attribute which is restricted to having a name (any permitted scalar values allowed, too).

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:

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

    http://blog.mhartl.com/2008/09/21/mass-assignment-in-rails-applications/
    http://guides.rubyonrails.org/security.html
    http://railscasts.com/episodes/371-strong-parameters
    http://weblog.rubyonrails.org/2012/3/21/strong-parameters/
    https://github.com/blog/1068-public-key-security-vulnerability-and-mitigation