Topic: XSS and when h just ain't enough.
I'm just setting out developing with rails at the moment and one of the things I take a bit of an interest (as it's my day job) is website security.
Now I hope everyone will be familiar with the concepts of Cross-Site Scripting (XSS) and why it's a bad thing, but if not here's a brief overview.
Basically XSS attacks generally occur when a user of a site is able to pass code to a website which contains Javascript code, which is executed by the site when the page containing the users submission is rendered.
A classic example is a bulletin board site, if a user can enter a post which has
<script>alert("xss")</script>
and not have any of those characters escaped or removed, then they'll likely be able to execute any javascript as though it came from the source website.
So onto Rails. One of the standard pieces of advice I've seen for dealing with this problem in rails apps is to use the h() function whereever your putting content supplied by the user up onto the screen, and that is good advice...
but...
What about times where you can't do that. A good example is the in place editor field. If you try using h() there you will usually just end up breaking the javascript that runs the control.
My advice would be to look at santizing all your input data, at the point it gets submitted to your application, not just when it's replayed to the screen, that way you can avoid running the risk of missing an h() off somewhere or having the data output somewhere where you can't use it.
One method I've used to do this on a little app. I'm using to teach myself rails is this.
This is the controller method I use to create a new task in my todolist program
def create_task
params[:task].each do |key, value|
params[:task][key] = CGI::escapeHTML(value)
end
@task = Task.new(params[:task])
if @task.save
flash[:notice] = "New Task Saved OK"
redirect_to :action => :index
else
render :action => :new_task
end
end
The key lines are the first three which essentially iterate through the values for the task and escape any HTML characters in them (by the way you'll need require 'cgi' at the top of your controller for this to work)
Another option would be instead of escaping the characters in the form to simply strip any character classes you don't want from the data before saving it, using a similar mechanism...
hope this helps.