Rails XSS Filter
Posted on : 20-06-2007 | By : Tony Stubblebine | In : Uncategorized
Tags: foocamp, rails, security, xss
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.


A blog by
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/