Translations of this page?:

Proper scoping

For purpose's of illustration we'll be building a simple app to allow pet lovers to manage the loves of their life. Our models look like this:

class Pet < ActiveRecord::Base
  belongs_to :user
end
 
class User < ActiveRecord::Base
  has_many :pets
end

And our controllers looks a little like this:

class PetsController < ApplicationController
 
def edit
  @pet = Pet.find(params[:id])
end
 
def update
  @pet = Pet.find(params[:id])
  @pet.update_attributes(params[:pet]))
  redirect_to @pet
end
 
def create
  Pet.create(params[:pet]))
  redirect_to @pet
end

The problem

The problem is this line:

@pet = Pet.find(params[:id])

Our finds aren't scoped so our application is insecure. Any user can view and update any other users pet just by guessing id #s and passing them to our app.

/pets/48 might not be my pet, but our app above does nothing to prevent me from editing pet 48 and then saving my changes.

The solution

The solution is to properly scope finds using their parent objects:

  @pet = current_user.pets.find(params[:id])
  @pet = @active_account.pets.find(params[:id])

The full example below assumes we're using restful_auth (which provides the current_user helper), but scoping can be done anytime you know the parent record.

class PetsController < ApplicationController
 
def edit
  @pet = current_user.pets.find(params[:id])
end
 
def update
  @pet = current_user.pets.find(params[:id])
  @pet.update_attributes(params[:pet]))
  redirect_to @pet
end
 
def create
  current_user.pets.create(params[:pet]))
  redirect_to @pet
end

Now when a user tries to game your app and access a pet that isn't theirs they will see an error page. Your app is now more secure thanks to proper scoping.

 
howtos/security/scoping.txt · Last modified: 2009/02/17 03:11 by dreamer3
 
Recent changes RSS feed Creative Commons License