Raising Protected Attribute Assignment Errors

While mass-assignment in Rails can be convenient for developers, it can pose a security risk if the implications aren’t understood. An article on Rails Spikes does a good job of explaining the issue:

By default ActiveRecord allows visitors access to any writer method, that is, any method ending with an equal sign. This comes courtesy of the ActiveRecord::Base#attributes= method, which is used internally by the main methods that handle creating and updating records, including new(), create(), and update_attributes().

The way most applications are designed means that whatever data a visitor sends to the server will likely find its way through the attributes=() method, and if not protected, ActiveRecord will happily update the records based on what was sent. In less technical terms: ActiveRecord is insecure by default.

I suggest reading over that article, even if you’re familiar with the potential issues around mass-assignment. There’s also a Railscasts episode on the subject.

The solution proposed is to use attr_accessible in all of your models. This way, you have to explicitly make attributes accessible to users, which is generally a good thing. However, this strategy introduces a small “gotcha” that’s bitten me a few times.

When you’re in development and try to mass-assign a protected attribute, it will fail silently, leaving only a note in the debug log. I don’t know about you, but I very rarely look at the debug log, and I’ve found myself temporarily stumped when attributes weren’t being assigned as expected. Of course, I’m getting better about remembering to add attributes via attr_accessible after being bitten by this one a few times, but perhaps others have been confounded by this gotcha as well?

Well, thanks to a small change in Active Record (more detail here), it’s now possible to give yourself a more noticeable warning when your testing your application. Simply add the following initializer, and your tests will complain much more loudly if you try to mass-assign a protected attribute.

# config/initializers/noisy_protected_attribute_removal.rb
if Rails.env.test?
  ActiveRecord::Base.class_eval do
    def log_protected_attribute_removal(*attributes)
      raise "Can't mass-assign these protected attributes: #{attributes.join(', ')}"
    end
  end
end

This little trick has saved me some head-scratching already. Perhaps you’ll find it useful as well.

Published by

Trevor Turk

A chess-playing machine of the late 18th century, promoted as an automaton but later proved a hoax.

3 thoughts on “Raising Protected Attribute Assignment Errors”

  1. Thanks for the tip. I tend to use Shoulda now, which comes with a a macro for testing that certain attributes of a model are protected.

    This can help too, when you do test-first development:

    should_protect_attributes :password

  2. Thanks for the link! We've been using the auto-attr_accessible in all our projects lately and it works very well…with the exception of the occasional lack of warnings.

    ActiveRecord used to throw exceptions about this a while back but it was removed. Good to see that you can now add it back as needed.

Comments are closed.