Updating database entries through ActionController

Guys,

I’ve just thought of the following situation: When updating a database
entry ruby calls x/update/7 where 7 is the database id. Now if someone
was to copy a form locally and change the form action to 8 (lets assume
they don’t have rights to number 8), then would the update work?
Presumably we could add an action to check the user does in fact own the
id number they are trying to update.

However what if that number was 9 and they also owned 9, then they’d
update their own entry (ok serves them right for messing with the system
I guess).

Does rails have some clever way of checking this or do I need to it
manually?

Cheers,

George

Well, in a multi-user system where people shouldn’t be able to see each
others’ data, then you definitely need some sort of row-based security
system in place, whereby you check any action that shows or updates data
by an :id parm to make sure that the current user is the owner of that
id. In this manner, the first situation you describe would fail on that
check.

As you said, if they change the form and run it for an id that they also
own, then shame on them and they deserve what they get. However, as a
good system developer you should probably guard against that.

One way would be to generate something like an MD5 hash value to store
on the table at the time the value is created, and include that as a
hidden field in the form that does the update. Generate the hash from
datetime value + some arbitrary passphrase. Your controller checks the
hash value submitted from teh form against the MD5 hash in the table
before making updates. Since the MD5 hash value is something that could
not be guessed easily, or at all, it will be impossible for the user to
submit an update to :id => 9, for instance, unless they specifically go
through your system and the form they submit has the appropriate MD5
hash.

c.

George P. wrote:

Guys,

I’ve just thought of the following situation: When updating a database
entry ruby calls x/update/7 where 7 is the database id. Now if someone
was to copy a form locally and change the form action to 8 (lets assume
they don’t have rights to number 8), then would the update work?
Presumably we could add an action to check the user does in fact own the
id number they are trying to update.

However what if that number was 9 and they also owned 9, then they’d
update their own entry (ok serves them right for messing with the system
I guess).

Does rails have some clever way of checking this or do I need to it
manually?

Cheers,

George

George P. wrote:

Guys,

I’ve just thought of the following situation: When updating a database
entry ruby calls x/update/7 where 7 is the database id. Now if someone
was to copy a form locally and change the form action to 8 (lets assume
they don’t have rights to number 8), then would the update work?
Presumably we could add an action to check the user does in fact own the
id number they are trying to update.

However what if that number was 9 and they also owned 9, then they’d
update their own entry (ok serves them right for messing with the system
I guess).

Does rails have some clever way of checking this or do I need to it
manually?

Cheers,

George

You describe the convention, but none of that is what “rails does”,
since it’s up to the programmer to do anything beyond the basic CRUD.
To keep security, can simply only allow them edit the ones that belongs
to them.

Assume:
Item has_many :users

def update
@item = Item.find(params[:id])

if @item.user == session[:user]
@item.update_attributes(params[:item])
redirect_to :action => ‘show’, :id => @item
else
render :text => ‘Hacker!’
end
end

Alex W. wrote:

George P. wrote:

Guys,

I’ve just thought of the following situation: When updating a database
entry ruby calls x/update/7 where 7 is the database id. Now if someone
was to copy a form locally and change the form action to 8 (lets assume
they don’t have rights to number 8), then would the update work?
Presumably we could add an action to check the user does in fact own the
id number they are trying to update.

However what if that number was 9 and they also owned 9, then they’d
update their own entry (ok serves them right for messing with the system
I guess).

Does rails have some clever way of checking this or do I need to it
manually?

Cheers,

George

You describe the convention, but none of that is what “rails does”,
since it’s up to the programmer to do anything beyond the basic CRUD.
To keep security, can simply only allow them edit the ones that belongs
to them.

Assume:
Item has_many :users

def update
@item = Item.find(params[:id])

if @item.user == session[:user]
@item.update_attributes(params[:item])
redirect_to :action => ‘show’, :id => @item
else
render :text => ‘Hacker!’
end
end

#1 line less

def update
if @item = current_user.items.find_by_id(params[:id])
@item.update_attributes(params[:item])
redirect_to :action => ‘show’, :id => @item
else
render :text => ‘Hacker!’
end
end

Gokhan
www.sylow.net

Presumably the data that you have for the user has some link to the
user.
Ie

class User< AR::B
has_many :things
end

class Thing <AR::B
belongs_to :user
end

There are a couple of options that come to mind to scope these objects
to
their owners.

  1. use with_scope. This can help with this area and is available in the
    docs.

  2. follow the chain of ownership. eg

current_user.things.find( params[:id] )

If the thing does not belong to the user, it will be nil.

Either or both of these should do what you need.

Hope that helps

George -

All user input needs to be considered malicious until you evaluate
otherwise. The use of params[:id] as in your example is a prime example
of this problem - you are responsible for either (1) verifying that the
user owns the ID when the update is called, or (2) prevent the problem
altoghether by using something other than a URL-based ID to identify
the record (such as by using a session variable rather than the ID
parameter to “remember” the id of the record that is to be updated).

There is no built-in magic in rails to manage this problem for you…