Preventing XSS from entering your database

I had all of our data being html-escaped as it was rendered to the page, but the problem is that other systems interact with ours — we send data to web analytics systems and to SalesForce.com. In that case you can’t count on escaping entities on display — you need to catch it on the way into your database.

I found a few sites with some fixes, though most were still focused on cleaning the data on display. I ended up taking Rick’s plugin and applying it at save time in the model object. I’m not sure it’s the cleanest — I’d almost certainly say there is a more elegant way to do this — but this was quick and works great.

It’s still basically designed to be used at output time:

<%= white_list @article.body %>

But instead I include the helper directly to a model and overwrite the attribute setters:


class Contact < ActiveRecord::Base

include WhiteListHelper

def name=(text) write_attribute(:name, white_list(text)) end

end

I tried setting up a before_filter and stepping through the param[] object, but my data was fairly simple and the above was dead easy.

Migrate Away your Cruft

Last summer I developed my first Rails application under a very tight deadline. I cut a few(!) corners and one was not creating a link from my Person table to my Team table for the team coach.

So I’m trying to clean up after myself a bit. It turns out that I can get about 90% of the way there for just a few quick lines of code:

class AddFieldsToTeam < ActiveRecord::Migration
  def self.up
    add_column :teams, :coach_id, :integer
    add_column :teams, :asst_coach_id, :integer

    Team.reset_column_information

    @teams = Team.find(:all)
    @teams.each do |t|
      c = Person.find_by_full_name t.coach
      ac = Person.find_by_full_name t.asst_coach
      if !c.nil? || ac.nil?
        t.coach_id = c.id unless c.nil?
        t.asst_coach_id = ac.id unless ac.nil?
        t.save
      end
    end
  end

  def self.down
    remove_column :teams, :coach_id
    remove_column :teams, :asst_coach_id
  end
end

Here’s the findby_fullname:

  def self.find_by_full_name(fn)
    name = fn.split
    find(:first, :conditions => ["void = 0 and first_name = ? and last_name = ?", name.first, name.last])
  end

That’s just too easy.