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?
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?
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>
Or with this plugin - no need for h 8)
http://railspikes.com/2008/1/28/auto-escaping-html-with-rails
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></script>')
# => <script src=http://ha.ckers.org/xss.js&gt;&lt;/script&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...
There are three basic approaches to this problem.
h()
in your views. The downside here is that if you forget, you get pwnd.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()
.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.
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.