ruby-on-railsstrong-parameters

Rails When should I use strong parameters?


I am not sure if I understand the concept of strong parameters correctly. I should use strong parameters to params that I will use only to edit some data? Or I should use them for every params I want to get in controller? For example I want to get data between two dates, so I need date1 and date2 as params. Should I use here strong params or not?


Solution

  • The easiest way to understand when you should use strong parameters is to understand what a mass assignment volunerability is. In Rails 3 you could do the following:

    class CreateUsers < ActiveRecord::Migration[3.0]
      def change
        create_table :users do |t|
          t.string :email
          t.string :encrypted_password
          t.boolean :admin
          t.timestamps
        end
      end
    end
    
    
    class UserController < ApplicationController
      def create
        @user = User.new(params[:user])
        if @user.save
          redirect_to @user
        else
          render :new
        end
      end 
    end
    
    

    Here we are just passing a "hash" (its actually an ActionController::Parameters instance) straight into the model. All a malicous user has to do here is request:

    POST /users?users[admin]=1 
    

    And they have created an admin account. In 2012 Egor Homakov famously exploited one such loophole in Github to commit to the Rails repository.

    Such an attack is trivial to perform with cURL or by using the web inspector to manipulate a form.

    If we whitelist which attributes the user should be able to pass:

    class UserController < ApplicationController
      def create
        @user = User.new(
          params.require(:user)
                .permit(:email, :password, :password_confirmation)
        )
        if @user.save
          redirect_to @user
        else
          render :new
        end
      end 
    end
    

    Then this avoids the vulnerability - strong parameters is really just a simple DSL for slicing and dicing nested hash like structures. What changed in Rail 4 is that when you pass a n instance of ActionController::Parameters to a model an exception is raised unless calling #permitted? on the parameters object returns true. This avoids a mass assignment vulnerability from occuring simply due to programmer laziness or ignorance.

    It does not sanitize your inputs in any other way. Like for example it won't prevent SQL injection or remote code execution if you treat user input carelessly.

    You don't need strong parameters if you're passing parameters one by one like in this very contrived example:

    class UserController < ApplicationController
      def create
        @user = User.new do |u|
          u.email = params[:user][:email]
          u.password = params[:user][:password]
          u.password_confirmation = params[:user][:password_confirmation]
        end
        if @user.save
          redirect_to @user
        else
          render :new
        end
      end 
    end