Well, it seems I jumped the gun. In Security issue in Liquid::Template, I thought I had a found a problem with the Liquid template engine. Instead, I should have looked more closely at what I do:

app/controllers/pages_controller.rb

1 class PagesController < ApplicationController
2 def show
3 # …
4 render(:inline => @page.render, :layout => false)
5 end
6 end

The details can be found at #render on the Ruby on Rails API. Seems like it’s time for us to switch to using render :text.

I am sorry for any scare I caused. If I had run a separate test case, I’d have immediately seen I was in error, and not Liquid.

In XLsuite, we use Liquid templates in the CMS. Two days ago, I noticed a big problem: ERB code in the Liquid template ends up being eval’d. This is in direct contradiction with Liquid’s mission statement:

Ruby library for rendering safe templates which cannot affect the security of the server they are rendered on.

From Liquid Home Page

I’m reposting this here so this gets the attention it deserves.

If you are interested, you can view Liquid’s issue at: http://code.google.com/p/liquid-markup/issues/detail?id=6

I just hit something very interesting today. You remember about attr_accessible, right ? And you use it to protect your models from injection, right ?

Anyway, I added attr_accessible to my models and then ran my tests. BAM! Hundreds of errors. Ooops, time to revert and go slowly here.

Let’s take one example:

app/models/tournament.rb

1 class Tournament < ActiveRecord::Base
2 belongs_to :game
3 validates_presence_of :game_id
4 end

We want to protect Tournament from injection attacks. The accessible columns are: name, game_id. So, let’s add that:

app/models/tournament.rb

1 class Tournament < ActiveRecord::Base
2 belongs_to :game
3 attr_accessible :name, :game_id
4 validate do |tournament|
5 tournament.errors.add_to_base("Game must be active") unless tournament.game.active?
6 end
7 end

Run the tournament tests, and chaos ensues. Looking at the errors, I can see a recurring pattern: all of my tests are complaining about a NoMethodError active? on NilClass. What ? Look here, buddy, I am giving you a game:

test/unit/tournament_test.rb

1 class TournamentWithGameTest < Test::Unit::TestCase
2 fixtures :games
3
4 def setup
5 @tournament = Tournament.create!(:game => Game.find(:first),
6 :name => My Tournament)
7 end
8 end

The fix is very obvious, once you think about it:

app/models/tournament.rb

1 class Tournament < ActiveRecord::Base
2 belongs_to :game
3 attr_accessible :name, :game_id, :game
4 validate do |tournament|
5 tournament.errors.add_to_base("Game must be active") unless tournament.game.active?
6 end
7 end

Since ActiveRecord::Base is doing a straight key removal from the attributes Hash when using attr_accessible, it is important to also include any relational attributes as well.

UPDATE 2006-12-06: Trevor Squires is the author of the post I was searching for. Both of his articles are referenced above.

If you thought you were secure, think again.

Like many, I am using Capistrano to deploy my Rails application. Like many, I also unintentionaly show Subversion metadata to the world.

In Preventing Subversion Exposure, Dan Benjamin talks about how to secure your server if you are using Apache:




httpd.conf

1 <directorymatch "^/.*/\.svn/">
2 Order deny,allow
3 Deny from all
4 </directorymatch>

I am using a clustered deployment environment as described on Mongrel’s LighTTPD page:

Except LighTTP is replaced with Pound, and Apache is just another service.

My pound.cfg contains this block of code:

pound.cfg

1 # static file serving
2 Service
3 URL ".*\.(jpe?g|gif|png|js|css|xml)"
4 BackEnd
5 Address 127.0.0.1
6 Port 12600
7 End
8 End
9
10 Service
11 BackEnd
12 Address 127.0.0.1
13 Port 12500
14 End
15 End

I thought I was not vulnerable to Dan’s trick, but it turns out I am.

When Pound receives the request, it attempts to match the incoming Path with the URL above. Since /.svn/entries does not match, Pound proceeds with the next service. Mongrel has the ability to serve static files too, and it turns out that it is Mongrel which is opening up the security hole.

Until I find how to correct the hole, I am now deploying using the export method:

config/deploy.rb

1 set :checkout, "export"

UPDATE (2006-08-25): Following "John’s ":#comment-139 suggestion below, you can also change the Pound configuration to this:

pound.cfg

1 # static file serving
2 Service
3 URL ".*\.(jpe?g|gif|png|js|css|xml|svn)"
4 BackEnd
5 Address 127.0.0.1
6 Port 12600
7 End
8 End

Note where “svn” was added to the end of the URL configuration line ? That tells Pound to send requests for “.svn” to this service (Apache in my case) where the 403 can be processed.

You could also change the URL line to handle CVS, darcs and other version control admin directories.

Search

Your Host

A picture of me

I am François Beausoleil, a Ruby on Rails and Scala developer. During the day, I work on Seevibes, a platform to measure social interactions related to TV shows. At night, I am interested many things. Read my biography.

Top Tags

Books I read and recommend

Links

Projects I work on

Projects I worked on