blog.mhartl | Michael Hartl's tech blog

2008-09-21

Mass assignment in Rails applications

Filed under: Ruby on Rails, mass assignment — mhartl @ 18:13

This is a brief review of mass assignment in Rails. See the follow-up post on Finding and fixing mass assignment problems in Rails applications for some more tips on how to find and fix mass assignment problems.

We’ll begin with a simple example. Suppose an application has a User model that looks like this:

# == Schema Information
# Table name: users
#
#  id                         :integer(11)     not null, primary key
#  email                      :string(255)
#  name                       :string(255)
#  password                   :string(255)
#  admin                      :boolean(1)      not null
class User < ActiveRecord::Base
  validates_presence_of :email, :password
  validates_uniqueness_of :email
  .
  .
  .
end

Note the presence of an admin boolean to identify administrative users. With this model, the Users controller might have this standard update code:

  def update
    @user = User.find(params[:id])

    respond_to do |format|
      if @user.update_attributes(params[:user])
        flash[:notice] = 'User was successfully updated.'
        format.html { redirect_to(@user) }
      else
        format.html { render :action => "edit" }
      end
    end
  end

This works fine, but note that the line

  if @user.update_attributes(params[:user])

performs an update to the @user object through the params hash, assigning all the @user attributes at once—that is, as a mass assignment.

The problem with mass assignment is that some malicious [cr|h]acker might write a script to PUT something like name=New+Name&admin=1, thereby adding himself as an administrative user! This would be a Bad Thing™. The standard solution to this problem is to use attr_accessible in the model to declare explicitly the attributes that can be modified by mass assignment. To protect our User model, for example, we would write

class User < ActiveRecord::Base

  attr_accessible :email, :name, :password

  validates_presence_of :email, :password
  validates_uniqueness_of :email
  .
  .
  .
end

Since :admin isn’t included in the attr_accessible argument list, the User model’s admin attribute is safe from unwanted modification.

This seems simple enough, but the rub is that remembering to protect against mass assignment is difficult. Using mass assignment doesn’t affect the normal operations of the site, so it’s hard to notice the problem. Moreover, although you could shut off mass assignment globally, often there are many models that are used internally and never get modified directly by a web interface. Not being able to use mass assignment for these models is inconvenient, and manually making all attributes attr_accessible is cumbersome and error-prone. So, what’s a Rails developer to do?

Spurred by an email from Eric Chapweske of Slantwise Design, I recently audited the Insoshi social network for mass assignment vulnerabilities. Doing this manually was annoying, so in the process I developed a simple plugin to find likely vulnerabilities automatically, by searching through the controllers for likely mass assignment and then looking in the models to see if they didn’t define attr_accessible. The result is a list of potential trouble spots.

To use the find_mass_assignment plugin, simply install it from GitHub as follows:

$ script/plugin install git://github.com/mhartl/find_mass_assignment.git

(You’ll need Git and Rails 2.1 or later for this to work.) The plugin defines a Rake task to find mass assignment vulnerabilities; running it on the example Users controller from above would yield the following:

$ rake find_mass_assignment

/path/to/app/controllers/users_controller.rb
  5  if @user.update_attributes(params[:user])

This tells us that line 5 in the Users controller has a likely mass assignment vulnerability.

The find_mass_assignment plugin doesn’t fix mass assignment problems automatically, but by making it more convenient to find them I hope it can significantly improve the odds that they will be caught (and fixed!) quickly.

1 Comment »

  1. [...] alerting me to mass assignment vulnerabilities in the Insoshi social network sourcecode. (See my post on mass assignment for a quick review of the concept.) I quickly set to work fixing the problems, and within a few [...]

    Pingback by Finding and fixing mass assignment problems in Rails applications « Insoshi Ruby on Rails blog — 2008-09-21 @ 18:22


RSS feed for comments on this post. TrackBack URI

Leave a comment

Blog at WordPress.com.