views:

4187

answers:

5

What is the recommended way to escape HTML to prevent XSS vulnerabilities in Rails apps?

Should you allow the user to put any text into the database but escape it when displaying it? Should you add before_save filters to escape the input?

+4  A: 

Use the h method in your view template. Say you have a post object with a comment property:

<div class="comment">
    <%= h post.comment %>
</div>
Jason Punyon
+2  A: 

Or with this plugin - no need for h 8)

http://railspikes.com/2008/1/28/auto-escaping-html-with-rails

Reuben Mallaby
+3  A: 

The h is an alias for html_escape, which is a utility method for escaping all HTML tag characters:

html_escape('<script src=http://ha.ckers.org/xss.js&gt;&lt;/script&gt;')
# => &lt;script src=http://ha.ckers.org/xss.js&amp;gt;&amp;lt;/script&amp;gt;

If you need more control, go with the sanitize method, which can be used as a white-list of tags and attributes to allow:

sanitize(@article.body, :tags => %w(table tr td), :attributes => %w(id class style))

I would allow the user to input anything, store it as-is in the database, and escape when displaying it. That way you don't lose any information entered. You can always tweak the escaping logic later...

Daniel Perez Alvarez
+9  A: 

There are three basic approaches to this problem.

  1. use h() in your views. The downside here is that if you forget, you get pwnd.
  2. Use a plugin that escapes content when it is saved. My plugin xss_terminate does this. Then you don't have to use h() in your views (mostly). There are others that work on the controller level. The downsides here are (a) if there's a bug in the escaping code, you could get XSS in your database; and (b) There are corner cases where you'll still want to use h().
  3. Use a plugin that escapes content when it is displayed. CrossSiteSniper is probably the best known of these. This aliases your attributes so that when you call foo.name it escapes the content. There's a way around it if you need the content unescaped. I like this plugin but I'm not wild about letting XSS into my database in the first place...

Then there are some hybrid approaches.

There's no reason why you can't use xss_terminate and CrossSiteSniper at the same time.

There's also a ERb implementation called Erubis that can be configured so that any call like <%= foo.name %> is escaped -- the equivalent of <%= h(foo.name) %>. Unfortunately, Erubis always seems to lag behind Rails and so using it can slow you down.

If you want to read more, I wrote a blog post (which Xavor kindly linked to) about using xss_terminate.

Luke Francl
Your plugin works great. thanks!
bandhunt
A: 

I've just released a plugin called ActsAsSanitiled using the Sanitize gem which can guarantee well-formedness as well being very configurable to what kind of HTML is allowed, all without munging user input or requiring anything to be remembered at the template level.

dasil003