Quick Note on Ruby on Rails Security
Published: December 1st, 2007Lately I’ve been intrigued by the different ways you can exploit a websites architecture; by learning these ways I’ve found that many sites don’t protect themselves. Luckily, Ruby on Rails makes it pretty easy to protect your site from the most common attacks.
The Ruby on Rails security issue that I’d like to remind you of is mass assignment, or more notably described; setting any attribute a user may want at his will. You may or may not know of this, so I’ll give you a run down.
You create a model, it has CRUD actions in the controller. Hacker_001 comes to your site and signs up for an account. Before he submits it, he edits the form to include this:
<input type="hidden" id="role" name="user[role]" value="admin" />
On submission, the parameters passed to the controller will essentially set him as an admin if you have a similar setup for roles. This same technique can be used in every single scenario you can think of that has attributes which are not protected. This means Hacker_001 can change the ownership of x, y, z comment to another user’s name. He really has the site under his control as long as you keep it open.
Black List Approach
There’s two ways you can protect yourself. First, you can deny access to specific attributes in your model with the attr_protected1 declaration:
class User < ActiveRecord::Base attr_protected :role end
Now, when the params come in with role on creation, it’ll simply be ignored. This technique definitely solves the problem, but I stick to a more verbose and secure strategy.
White List Approach
Now it’s time to introduce you to the “white list” approach. What you do in this scenario is specifically say which attributes are writable, all the others will be automatically protected. The method you use is attr_accessible2:
class User < ActiveRecord::Base> attr_accessible :name, :email, :password, :password_confirmation end
Now the only attributes that can be written to are explicitly declared in the model. This strategy has a lot more weight to it than the previous one. Think of it like a common PC firewall approach. Deny everything first, then explicitly declare what you want to be accepted to go through.
Well, there’s my first security tip. If I find some more to share I’ll post what I can. If anyone would like to add to this post, please feel free to do so. I’d love to learn more about this, and it’s always good to teach the other readers!
- http://ar.rubyonrails.com/classes/ActiveRecord/Base.html#M000358 [↩]
- http://ar.rubyonrails.com/classes/ActiveRecord/Base.html#M000357 [↩]

I think you’ve got the terms reversed, attr_accessible is Whitelisting, while attr_protected is Blacklisting.
I believe the attr_accessible is the more secure and safer approach. You make a decision about what you allow to be set, and protect everything else by default.. the classic firewall approach.
Even still attr_accessible is only the first line of defense. Liberal usage of the validates_* methods should be used to specify constraints for each attribute as well. I generally start by making the DB columns as restrictive as the underlying DB engine allows in terms of length/precision/type, etc, while still allowing for expected data. Then I match the validates_* methods to each column’s constraints. Finally I top it off with domain specific constraints; this part really is the key.. and the hardest part to get right.
Thanks for pointing that out, I just corrected it.
I completely agree with everything you said!
[...] Daniel Fischer - Got Fisch? » Quick Note on Ruby on Rails Security (tags: programming rails ruby rubyonrails) [...]
Good example…I have all my writeable stuff behind an admin interface, but good to know that publicly writable areas will need to be whitelisted before going to the db.
Ready. Set. Go.
In terms of the formatting, you're allowed to use markdown, textile, or basic html; it's truly up to you -- what strikes your fancy?
You don't have to worry about your e-mail address being sold to a russian-spam-mafia. I'm only going to use it for my own weird needs; like asking you out for a date on a lonely night of coding.