Recipe 11.4. Restricting Access to Public Methods or Actions


Problem

The default Rails routing system tends to make it obvious what actions are called by specific URLs. Unfortunately, this transparency also makes it easier for malicious users to exploit exposed actions in your application. You want to restrict access to public methods that expose or change information specific to individual users or accounts.

Solution

All public methods in your controllers are, by definition, actions. This means that without any other access control, these methods are available to all users.

You need to ensure that actions that display or change private data can be used only by users who are logged in, and that these users can access only their own data. The following show action of the Profiles controller demonstrates how you can use :user_id of the session hash in conjunction with the contents of the params hash to ensure this action acts only on the data of the user that calls it:

class ProfilesController < ApplicationController      def show     id = params[:id]     user_id = session[:user_id] || nil     @profile = Profile.find(id, :conditions => [ "user_id = ?", user_id])   rescue     redirect_to :controller => "users", :action => "list"   end      # ... end

Here, the :user_id from the session hash (or nil if the user isn't logged in) is used in conjunction with :id from the params hash, to retrieve a Profile object. If user_id is nil, then the conditions of Profile#find will prevent a Profile object (specified by id) from being returned.

Discussion

You don't have to do anything special to make the public methods of your controller accessible to users of your application. It follows that if a method is not to be called by methods outside the current class, you should make sure to make it private (using the private keyword). The following makes display_full_profile a private method and prevents it from being called outside of the ProfilesController class definition:

class ProfilesController < ApplicationController      def show     # ...   end      private     def display_full_profile       # ...     end end

Making methods private prevents them from becoming actions (publicly accessible), but even public methods should have some restrictions on how they are called. The solution demonstrates how you can restrict methods to act only on the data of the currently logged-in user.

The show action in the solution finds and displays a user's profile using an id parameter that is passed in from the current user's session hash along with the :user_id. The extra information from the session is passed to the find method's :conditions attribute, using the bind variable syntax to prevent SQL injection. Doing this prevents users from altering or viewing data associated other users.

It's good practice to treat all actions that act on private data with this kind of restrictive precaution. You'll also want to add tests to your test suite to make sure that users can act only on their own data.

Another way to prevent malicious manipulation of actions is to explicitly restrict columns that Active Record methods such as create and update_attributes act on. Do this by calling the attr_protected macro in your model class definition; for example:

class Profile < ActiveRecord::Base   attr_protected :bonus_points   belongs_to :user end

Using attr_protected prevents the following update method in the Profile controller from accessing the bonus_points attribute of the Profile model:

def update   @profile = Profile.find(params[:id])   if @profile.update_attributes(params[:profile])     flash[:notice] = 'Profile was successfully updated.'     redirect_to :action => 'show', :id => @profile   else     render :action => 'edit'   end end

Any attribute you pass to attr_protected will be protected in this way. The inverse of this approach is to restrict updates on all model attributes, allowing them explicitly with att_accessible. If this macro is used, only those attributes that it names are accessible for mass assignment.

See Also

  • Section 4.12"




Rails Cookbook
Rails Cookbook (Cookbooks (OReilly))
ISBN: 0596527314
EAN: 2147483647
Year: 2007
Pages: 250
Authors: Rob Orsini

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net