Prevent cross-site scripting in rails-2.3.5 using rails_xss plugin1
In previous rails versions, to prevent cross-site scripting, the h helper method must be called explicitly to escape the output to the response body. The rails_xss plugin replaces the default ERB template handlers with eruibs, and switches the behavior to escape by default rather than requiring you to escape. This behavior is consistent with Rails 3.0. Install rails_xss using the following commands:
sudo gem install erubis ruby script/plugin install git://github.com/NZKoz/rails_xss.git
By default a string is considered unsafe and is escaped by rails. If you have your own helpers you should tell Rails that these strings are safe using html_safe! method. If you want to display the string as HTML code instead of escaping it you just call html_safe! on the string object. As an example before installing rails_xss:
<%= "<h1>Hello, World!</h1>" %> # not escaped <%=h "<h1>Hello, World!</h1>" %> # escaped
but after installing rails_xss by default a string is considered unsafe and will be escaped
<%= "<h1>Hello, World!</h1>" %> # escaped <%= "<h1>Hello, World!</h1>".html_safe! %> # not escaped <%= raw "<h1>Hello, World!</h1>" %> # not escaped
This helps in escaping any user-entered data in your application like comments. More information about rails_xss can be found at rails_xss
This escaping behavior will be painful if your application contains user-entered data, but from trusted sources like a blog. A blog contains many places that you don't want this behavior to be the default action. You will need to call html_safe! method in all the places you emit code to the view through strings. This behavior can be altered by adding a class method in ActiveRecord::Base class that will mark all the specified columns in a model as safe. This will make all blog models safe, and we won't need to call html_safe! every where in the views.
In the config/initializers directory create "html_safe_attributes.rb" file; this file will be loaded every time you start the server. First we extend the ActiveRecord::Base class with the module that will contain our html_safe_attributes class method.
class ActiveRecord::Base
def self.inherited_with_html_safe_attributes(klass)
inherited_without_html_safe_attributes(klass)
klass.extend(HTMLSafeAttributes)
end
class <<self
alias_method_chain :inherited, :html_safe_attributes
end
end
module HTMLSafeAttributes
def html_safe_attributes(*attrs)
cols = attrs
cols = columns.select { |col| col.type == :string || col.type == :text }.map(&:name) if attrs.first == :all
cols.each do |attr|
class_eval <<-STRING
def #{attr}
read_attribute(:#{attr}).html_safe!
end
STRING
end
end
end
class NilClass
def html_safe!
nil
end
end
We enhanced the NilClass with html_safe! because a column value may be nil, and this will throw an exception in the read_attribute method. Now inside a blog model you specify your safe attributes, or you specify :all to mark all string in the model as safe.
class BlogPost < ActiveRecord::Base
html_safe_attributes :all
end
Any column whose type is string or text will be marked as safe.

1 Comments
07/12/10 at 07:28:29
Looks nice... do you know of a clean way to accept only certain tags (like a in a comment system for example)? Thanks!
Leave a Comment...