Rails 3.2 attr_accessible, RailsAdmin, and "accessible by admins"
July 15, 2012
First of all, my blog is now back up! Instead of self hosting my Wordpress blog, now the fine people at ZippyKid host it. These guys are awesome: taking a mess of an import and making it Just Work. A+++ WOULD DO AGAIN
Now, back to real news…
The Problem: Security in Rails: Say hello to the secure boss (different from the old boss)
Because of some high profile Rails sites being hacked, Rails 3.2 changed the default Rails model behavior to “only let users (and developers) update attributes in this list”. This list varies by model.
A refresher into the hack
Rails has this clever feature where you can say, “update this record with the form data passed in”. A semi-clever hacker could use this ability to change fields that the Rails developer didn’t intend to be changed (“shove this value into the POST params, even though there’s no field named that on the HTML for this form”)
What Rails 3.2 did about it
Before Rails 3.2 You used to have models that look like: class User < ActiveRecord::Base
end
In Rails 3.2, now you have models that look like:
`class User < ActiveRecord::Base # Setup accessible (or protected) attributes for your model
attr_accessible :name, :email, :password, :password_confirmation end`
The attr_accessible
block says, “hey, that ‘update this record with form data passed in’ feature? That’s only allowed to touch these fields”.
In this example the name, email, password, and password_confirmation, but is NOT allowed to edit anything else. Perhaps you store access keys, or middle name in the User
model. You have to explicitly change these values, and not use the ‘update this record with form data’ shortcut.
Enough background: You said something about RailsAdmin?
RailsAdmin is a clever piece of software that automates creating an admin interface for your Rails site. You have simple access to create, read update or delete records in your site
… but how does it play with that attr_accessible
thing?
Glad you asked
Normally it works very well. You can see all the fields in your model, and if the attribute is not attr_accessible
, then RailsAdmin will display the value as read-only.
Read-only you say? But I have values I want admins to be able to edit, but I only want admins (not everyone) to edit them. How do I?
Returning to the access_keys
example, you want admins to be able to edit this value in RailsAdmin. You don’t want to make that attr_accessible
because then anyone can edit that setting (introducing a security hole).
The solution: attr_accessible
+ as
(a user)
attr_accessible
has an oft-forgot as
parameter. This allows you say, “this is allowed, only if I I’m doing this as a ______________ user
Using this feature you can declare models like
`class User < ActiveRecord::Base # Setup accessible (or protected) attributes for your model
attr_accessible :name, :email, :password, :password_confirmation, :as => [:default, :admin]
attr_accessible :access_key, as: :admin end`
access_key
will only be changable when you’re doing something as the admin
role, and the other attributes will be enable both for the default role and the admin role
Configuring RailsAdmin to use the admin role
In your config/initializers/rails_admin.rb
file, add the following line in the RailsAdmin.config do |config|
block
config.attr_accessible_role { :admin }
Conclusion
And that’s all there is to it: use as: :admin
, and configure RailsAdmin to post things “as an admin”. Good to go!