Advancing with Rails, day 3

Posted on April 25, 2008
Filed Under Rails, Ruby, Web |

The penultimate day of David Black's 'Advancing with Rails' course covered some of the more technical aspects of Rails application development.

Security

We had quite an extensive review of how you can make your Rails application more secure. Rails now by default ships with the protect_from_forgery option enabled in the ApplicationController. This helps to protect your application from cross-site forgery.

Any request (e.g. form input) to your application that comes without the forgery protection token fails with a InvalidAuthenticityToken error. The token is, by default, submitted as a hidden field in your form.

attr_accessible and attr_protected

One thing I haven't made use of in the past but I really like the look of are the attr_accessible and attr_protected macros.

Using these macros it is possible to whitelist and perhaps more importantly blacklist those attributes that can and cannot be updated. If you had for example a User model with attributes name, hashed_password and nickname you could have the following in your model:


attr_accessible :name, :nickname
attr_protected :hashed_password

This statements mean that whilst it is possible to update the attr_accessible parameters through form input, the attr_protected attributes can only by updated through explicit modification (and not via form/url input).

Preventing SQL injection

This has been covered lots before but I still think it's worth reiterating. When specifying conditions on ActiveRecord functions the conditions should be specified as an array rather than using parameters directly in the query.

An example of a vulnerable query would be something like:

User.find(:all, :conditions => "name = #{params[:name]}")

There are a couple of things wrong here. Firstly, the find method is taking conditions from the params and putting them directly into the query SQL. If someone decided to post a query with some SQL e.g.

DROP TABLE users;

You might find you've had your users tables hosed.

The second problem with this is that queries like this really belong in the model layer of your application. So, a better version of this (potentially) dangerous code would be:


class User < ActiveRecord::Base
  def self.find_by_name(name)
    find(:all, :conditions => ["name = ?", name])
  end
end

Then in your controller you call the function like this:


arfons = User.find_by_name("arfon")

The reason that this method of passing parameters to the query is safer is that Rails sanitises the parameters coming in thus protecting the database from a rogue query.

There was plenty more good stuff on day 3 including routes, URL recognition and REST but as it seems to be taking me an age to write up even the smallest part of the course I'm going to call it quits here…

Comments

Leave a Comment

If you would like to make a comment, please fill out the form below.

You must be logged in to post a comment.

Recently


Categories


Archives