Rails XSS Filter

Posted on : 20-06-2007 | By : Tony Stubblebine | In : Uncategorized

Tags: , , ,

4

I was pushed to put XSS protections into CrowdVine when one of the Foo Camper’s released this XSS crack into the Foo Camp social network. It causes a person to friend everyone in the network and then inserts itself into your profile. It was brutal. Worse it was a very simple and readable 49 lines of code. I took one glance at it and realized that even I know enough javascript to write one of these.

Looking around I saw two approaches for Rails. Run Safe ERB and force yourself to validate each individual input or run Rick Olson’s white list plugin.

I decided to use the white_list plugin to clean all values in params. It required a little bit of tweaking. Here’s the details.

Install the white list plugin:

script/plugin install -x http://svn.techno-weenie.net/projects/plugins/white_list/

Edit vendor/plugins/white_list/init.rb so that white_list is available in the Controller:


require 'white_list_helper'
ActionController::Base.send :include, WhiteListHelper

Add a filter to application.rb in order to walk the params hash:


before_filter :sanitize_params

def sanitize_params
# TODO: 2007-06-20  -- I found that this didn't
# work when called with params instead of @params. I assume
# I'm clueless in some important regard. (Many important regards?)
@params = walk_hash(@params) if @params and !site_owner?
end

def walk_hash(hash)
hash.keys.each do |key|
if hash[key].is_a? String
hash[key] = white_list(hash[key])
elsif hash[key].is_a? Hash
hash[key] = walk_hash(hash[key])
elsif hash[key].is_a? Array
hash[key] = walk_array(hash[key])
end
end
hash
end

def walk_array(array)
array.each_with_index do |el,i|
if el.is_a? String
array[i] = white_list(el)
elsif el.is_a? Hash
array[i] = walk_hash(el)
elsif el.is_a? Array
array[i] = walk_array(el)
end
end
array
end

Does this look right to people? Is there a more idiomatic ruby/rails way to do this? I’m a bit worried about how this will perform on very large chunks of data or on deeply nested hashes.

Comments (4)

Good work,

I think applying white_list to params is a big improvement on having to remember to add white_list every time you render some user submitted field in the view. (This seems to be the ‘rails way’ but it seems stupid to increase the load on the server by sanitizing the same text over and over again every time a page is viewed)

But that said I’m not sure why you are doing this to the controller rather than adding it as a validation in the model.

Thanx – I’ve been looking for a pre-emptive approach – this takes that approach

I wonder how the above will feel about uploads? I guess I’ll find out.

cheers,
Jodi

Hi, we found that if we changed the call to sanitize params to this:

walk_hash(params)

It will not report deprecation warnings for rails 1.2.6 (2.0.1 testing for white_list is coming soon)

Hope it helps some other folks.

We took some feedback and some help from Jodi (above) and packed this into a Rails plugin:
http://code.google.com/p/sanitizeparams/

Write a comment