How to secure records?

I have “users”, “company” and “contract” controllers, with the following
relations:

class User < ActiveRecord::Base
has_many :companies

class Company < ActiveRecord::Base
belongs_to :user
has_many :contracts

class Contract < ActiveRecord::Base
belongs_to :company

I had no problem using ruby to create management interface for it (and i
started programming in ruby two weeks ago!!). What concerns me is
security of records. Here’s what needs to be done:

  1. actions like for example /company/edit/1 should raise error when
    Company with id=1 doesn’t belong to logged User (i’m using login
    generator gem), same for Contracts (ownership needs to be checked
    through Companies table).

  2. system should be immune to hidden field abuse (like: download html
    for /company/edit/30, edit html and replace user_id, visit from
    localhost, submit to overtake record)

How to do that?? Here’s what i found so far:

  1. Use subselect/joins to check permission at the beginning of every
    chosen action in controller
    @contract=Contract.find_by_sql(‘select contract.* from “contracts” r
    left join “companies” p on p.“id”=r.“company_id” left join “users” …
    where user.“id”=’[email protected][‘user’].id)
    if not found then raise error…
    working, but ugly as hell and i’m repeating myslef often in different
    actions.

  2. Use :through property instead joins above (don’t know how to use it
    properly yet)

  3. Use validates_associated in model (doesnt protect from hidden field
    abuse, cannot work through many tables like
    Contract>o----Company>o----User - or can it??)

  4. Write validation of ownership in model, not controller, similiar to
    validates_associated but smarter

  5. ??Some ready-to-use stuf maybe??

Thanks for advices.

This is a really basic response, but it may give you an idea.

When you call your ‘company/edit’ action, just do this:

@user = User.find(session[:user_id]) # This assumes that you are using
cookies to authenticate
@company = @user.companies.find(params[:id])

This ensures that you are not editing companies out of scope for the
owning
user.

Does that help?

thanks for answer. that’s just how i’m doing it now.

question is - can such ownership check be moved to models?? so when we
get :id or @params[‘contract’].id for example in Contract class
subselect/join is performed to check if it really belongs to logged
user, and if not error is raised.

why??

  • because then scaffolded actions can be used for stuff like
    contract/update safely
  • no code copy/paste in every action in controller
  • one central ownership validation for controller is less error prone
    and easier to modify

Take a look at the authorization plugin:
http://www.writertopia.com/developers/authorization

I especially like the authorization DSL.

Off the top of my head, I can’t see a way to do this. It seems to be
out of
the scope w/ the MVC here, and that the controller really needs to be
handling this rather than the model.

Now, you could override the methods of your class so that they require
an id
to be passed to them for each action… but that sounds like a lot of
extra
work.

Maybe someone else has some insight here…

This is best practice in Rails anyway, but you should protect certain
attributes of your Model from being mass assigned - for example in the
way you’ve defined below by editing a form source and resubmitting.

The way to do that is to use the attr_protected command in your model
to declare attributes that can only be set manually in your code. They
cannot be set using bulk assignments from outside such as
Model.create(params[:model]).

e.g.

class Company < ActiveRecord::Base
attr_protected :user_id
end

Alternatively you can use attr_accessible to explicitly declare which
fields can be mass assigned from form query parameters. It’s up to you
as to which of the opt-in or opt-out models you go for.

There’s more information on this in section 21.4 (“Creating Records
Directly from Form Parameters”) in chapter 21 (“Securing Your Rails
Application”) of the Agile Web D. with Rails book. It’s really
worth reading as it covers this and many other factors in securing code

  • if so, go for the 2nd Edition beta book available at Pragmatic
    Programmers as it is covering the more recent changes to the Rails
    codebase.

Ian

I’m not sure if this fits well to your problem, but did you have a look
at http://perens.com/FreeSoftware/ModelSecurity/ ? It’s not really
maintained actively, but it seems quite stable anyway

cheers
Martin

Along with attr_protected and/or attr_accessible to limit write access
to fields from forms, you may be interested in the ScopedAccess plugin:

http://habtm.com/articles/2006/02/22/nested-with_scope

…which essentially lets you apply a with_scope clause as a filter at
the controller level.

Bbkr I juz wrote:

I have “users”, “company” and “contract” controllers, with the following
relations:

class User < ActiveRecord::Base
has_many :companies

class Company < ActiveRecord::Base
belongs_to :user
has_many :contracts

class Contract < ActiveRecord::Base
belongs_to :company

I had no problem using ruby to create management interface for it (and i
started programming in ruby two weeks ago!!). What concerns me is
security of records. Here’s what needs to be done:

  1. actions like for example /company/edit/1 should raise error when
    Company with id=1 doesn’t belong to logged User (i’m using login
    generator gem), same for Contracts (ownership needs to be checked
    through Companies table).

  2. system should be immune to hidden field abuse (like: download html
    for /company/edit/30, edit html and replace user_id, visit from
    localhost, submit to overtake record)
    … [snip]