Our Little Secret

October 20th, 2010

So wading through every single Railscast episode isn’t going as well as I had planned. Life keeps getting in the way. October is a very busy month. Halloween is very important to me and my family. And yes I do spend all month getting ready. Truthfully, I’ve been getting ready since August.

You do know that my brother is a horror filmmaker out in LA, right? Yup. Halloween is a busy time of year. And the theatrically of it all is just too hard for me to pass up.

In addition, it’s hard to stay focused on getting through these early episodes when more exciting things keep jumping out at me…. like the JQuery Conference this weekend. A whole lot of awesome.

But whether it takes a year or longer, I’ve made a commitment and I plan to stick to it. So, I’m combining three episodes once again into one blog post. They’re all related anyway. And I have a feeling that Ryan likely wrote this as one episode initially and then broke it out into three because he was busy as well. Shhh. It’s just our little secret, Ryan.

So, this threesome is more about security. Bottom line:

params  <-- don't trust it
cookies <-- don't trust it
session  <-- you can trust it


When the dev places the user input directly into an SQL query, there is potential to really mess up the db.

This is BAD:

@tasks = Task.find(:all,:conditions=>"name LIKE ’%#{params[:query]}%’")

Input a quote and everything after that is considered pure SQL.

if params[:query] = " ' " + "DROP DATABASE"

There are easy ways to escape conditions.

tasks = Task.find(:all, :conditions=> [ "name LIKE ?", "%#{params[:query]}%" ]

This still looks dangerous to me but Rails will actually escape this for you. You only need to worry about escaping input in find methods if you’re using the :conditions parameter. If you’re using the dynamic find_by methods then Rails will automatically escape any input which will ensure that you’re safe from SQL injection.

So Ryan, you’re saying that the code below is safe?

tasks = Task.find_by_name(params[:query])

Really? Let’s try it out.

query = " ' " + "DROP DATABASE"
tasks = Task.find_by_name(query)

Whew! I still got my db. ;-)


@user = User.new(params[:user])

Everything in the params[:user] hash is being sent to create the user record. Don’t ever trust the params hash. It could be anything.

One way to prevent problems is to set protection on your user model. attr_protected will disable mass assignment for the fields you want to protect.

So in Ryan’s example, he had a User model with a boolean field denoting whether or not a user is an admin. By setting attr_protected :admin in your user model, you’re preventing the admin field from being set.

Here’s another example:
stuff = {:login => "Hacker", :password => "hacked"}
@user = User.new(stuff)

When attr_protected :password is set, the code above will not update the password field. But this will:

@user.password = 'goodsecurity'

So, that’s good. But actually, its better practice to use attr_accessible to open the fields that you want to be set via mass assignment and automatically hide all the rest. This protects fields that can be set indirectly via associations.


Allowing the user to input nastiness to the site directly is bad news. Adding data to a table directly from a view is fraught with issues. Ryan shows an awesome example of this. Try going to your favorite insecure website and type in any input text box:

I can haz hack? alert('i haz hakked u')

If you see an alert box, then this site is vulnerable to Cross Site Scripting. To avoid this problem, you need to escape user input. In older version of rails, you needed to use h method.

Really annoying to have to remember to add h to all your views. Another way to do this is to sanitize the input in the controller. Perhaps best to do it in both places. Or better yet, upgrade to Rails 3.

Rails 3 adds XSS protection by default. This means that you no longer have to manually escape user input with the h helper, because Rails will automatically escape it for you.


But if you really wanna protect yourself, use html_safe. You can read up all about it and more on Yehuda’s blog: SafeBuffers and Rails 3.0.

Hey, let’s be careful out there.

Entry Filed under: Professional,Railscasts Project,Ruby on Rails

Leave a Comment


Required, hidden

Some HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Trackback this post  |  Subscribe to the comments via RSS Feed