Form Data Injection - How to protect against?

I might be missing something here, but it seems as if the conventions
used when building forms in Rails apps leave a lot of open holes for
people to mess things up. For instance, let's say I have a multi-user
community app with a simple user profile page where users can edit
their profile. Not uncommon.

Now, on that page they can change things like their name, web site, IM
info, etc. But with what seems to be standard practice of updating that
info, as so...

def update
  @user = User.find(params[:id])
  if @user.update_attributes(params[:user])
    etc., etc.

...it seems like you are open for major problems. Let's say you have a
role field on your model. It seems trivial to have someone inject their
own form data into the headers to add the equivalent of...

<input id="user_role" name="user[role]" type="hidden"
value="Administrator" />

...and have that be passed along with the .update_attributes method. Am
I wrong?

Is there some common practice of protecting against this that I am just
missing? And if this isn't common practice, it should be, shouldn't it?
There is the obvious blunt route of being super-careful and checking
every field of the model, regardless of whether it's on the form or
not, but I don't see that being practiced, so I thought maybe I'm
missing something.

You missed attr_accessible and it's partner attr_protected in the models. :slight_smile:

You are correct, and you are missing attr_protected and attr_accessible.

You are very right. I did. I just finished reading up about them. And
following other discussions on this topic. Like
http://www.ruby-forum.com/topic/54867

I pointed the people in #rubyonrails on freenode to this post and got a
quick answer from stympy about checking out attr_protected and
attr_accessible. Knowing that was the answer, I was able to find quite
a lot of data. I simply had the wrong search terms for getting my
question answered. :slight_smile:

Here's what you need...

http://manuals.rubyonrails.com/read/chapter/47

Dylan Bennett wrote:

Another thing you need to keep in mind is about 'access rights' to the
record, not just to fields within the record. I, as user_id = 10 can
go to /users/10;edit, but I cannot go to /users/1;edit.

In my user controller I have this:
  # I already declare basic authentication in my application.rb
  before_filter :verify_user, :except => [ :check_field, :create, :new,
:retrieve_password ]

protected
  def verify_user
    return true if params[:id].nil? || params[:id].to_i ==
session[:user]
    flash[:error] = "You are not allowed to see another users Settings
screen."
    redirect_to_default
    false
  end

and that works like a charm
Adam