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 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 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.
Discussion