Rails XSS Filter
Wednesday, June 20th, 2007I 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.
