Jan 12, 2007

Announcing Acts As Sanitized

When I was doing my talk on Rails security at RailsConf Europe I joked about delivering a magical plugin, acts_as_impenetrable, that solved all of your security needs. There’s still no magic bullet for security, but I’d like to contribute a smidge of code that brings us a step closer.



Rails has the ability to mitigate cross-site scripting attacks in the form of its ActionView::Helpers::TextHelpers#sanitize method. This method won’t catch every clever XSS out there, but it sure helps. Sadly, sanitize is unavailable by default from your models and controllers; the expected usage pattern is that you’ll handle sanitization in your view, ex: <%= sanitize(@story.title) %> or <%=h @story.body %>.



I don’t think that’s especially, uh, agile (or whatever). Neither is importing those TextHelpers into your controller and reassigning your models’ various attributes to sanitized versions of themselves before saving. It’s tedious, it’s repetitive, and it opens the door to careless errors. Are you sure that you know every field that gets displayed in your views, even after all those revisions and migrations?



My solution to this is a plugin: acts_as_sanitized. You use it like so:




class Comment < ActiveRecord::Base
acts_as_sanitized
end


That’s it. The plugin figures out which fields in your model are able to be sanitized at application runtime. If you’re not comfortable with that for some strange reason, you can also specify which fields you’d like sanitized. You can even tell it to strip all tags, not just the ones that the sanitize method in Rails handles (script and form). Plus no more monkeying around in your controllers, no more wasteful filtering in your views.



Install like so from the root directory of your Rails app:




script/plugin install http://code.al3x.net/svn/acts_as_sanitized/


Documentation is included in the README file, and there’s a decent suite of tests included.



There isn’t much to this plugin as it stands, but as XSS attacks become ever-more complicated, I’m hoping that this plugin evolves to detect and combat them. If you see attacks that are sneaking by sanitize and strip_tags, let me know! Bugs and patches are more than welcome.

5 comments:

al3x said...

<em>This comment was imported.</em>
Author: <a href="http://addictedtonew.com">John Nunemaker</a><br />
Posted: 2007-01-13 16:31:09<br />
Sweet. This looks like good stuff. I was just looking at "fasterh":http://rubyforge.org/projects/fasterh/ but why h at all if you can do it in the model. I'll be trying this out for sure.

Have you looked at Rick Olson's white list plugin? I know that is for the view but it has several "test cases":http://svn.techno-weenie.net/projects/plugins/white_list/test/white_list_test.rb which could be snagged and added to make sure that this baby is stopping everything. Just a thought.

al3x said...

<em>This comment was imported.</em>
Author: rick<br />
Posted: 2007-01-15 04:08:06<br />
sanitize won't pass those white_list test cases.

al3x said...

<em>This comment was imported.</em>
Author: <a href="http://www.lachaise.org/?lang=en">Philippe Lachaise</a><br />
Posted: 2007-03-15 14:30:56<br />
acts_as_sanitized cause my app to crash.
Upon investigation it appears that ActionView::Helpers::TextHelper#sanitize does not handle properly a nil parameter.

(and nil parameters DO happen !)

# File vendor/rails/actionpack/lib/action_view/helpers/text_helper.rb, line 221

def sanitize(html)
# only do this if absolutely necessary
if html.index("<") # html.nil? causes CRASH !
end
end

I wouldnt modify RoR code so I modified the calling acts_as_sanitized code :

Instead of

def sanitize_field(field)
self[field.to_sym] = sanitize(self[field.to_sym])
end

def sanitize_field(field)
html = self[field.to_sym]
self[field.to_sym] = sanitize(html) unless html.nil? # Crash-proof
end

Regards,
Philippe.

al3x said...

<em>This comment was imported.</em>
Author: <a href="http://www.al3x.net">Alex Payne</a><br />
Posted: 2007-03-15 19:45:07<br />
Your changes have been rolled in, Philippe. Thanks!

Red said...

Hey, has acts as sanitized been moved? Would it be possible if you could redirect me to the plugin? thanks