xss_terminate now Rails 2.2 ready; code now on GitHub

Posted by Luke Francl
on Friday, December 19

I had some coffee a bit too late yesterday and it inspired me to a boost of productivity on xss_terminate, my plugin that escapes HTML from your models when you save them.

xss_terminate now supports Rails 2.2. It is backwards compatible with Rails 2.0 and 2.1.

I also moved the plugin source to GitHub, and incorporated a bug fix from redinger.

You can install it using

script/plugin install git://github.com/look/xss_terminate.git

Auto-escaping HTML with Rails

Posted by Luke Francl
on Monday, January 28

One of the things I don’t like about Rails is that it doesn’t auto-escape HTML in user input. Forget one h call in your template and you’re screwed. Worse yet, before Rails 2.0, strip_tags and sanitize were flawed. Fortunately that’s been fixed. Django added auto-escaping even though it was a backwards incompatible change, but so far there doesn’t seem to be similar movement on the Rails front.

But I’m all about automating manual processes. So let’s fix this problem.

Sanitize before saving or before displaying? Or both?

Should you sanitize text before saving it or before displaying it?

It’s nice to not need to worry about doing anything extra in your views. However, if a field escapes your notice, you may be open for an attack.

I think your first line of defense should be model-level sanitization, but auto-escaping HTML is good backup. Doing both covers your bases at a cost of extra processing.

Introducing xss_terminate

xss_terminate is a plugin in that makes stripping and sanitizing HTML stupid-simple. It’s install and forget. And you can forget about forgetting to h() your output, because you won’t need to anymore. It’s based on acts_as_sanitized by Alex Payne but updated for Rails 2.0, and with some new features.

I like acts_as_sanitized but it’s not being maintained any more so Alex gave me the OK to take his code and do something different with it. Here’s what makes xss_terminate different:

  • It works with Rails 2.0.
  • It’s automatic. It is included with default options in ActiveReord::Base so all your models are sanitized. Period.
  • It works with migrations. Columns are fetched when model is saved, not when the class is loaded.
  • You can decide whether to sanitize or strip tags on a field-by-field basis instead of model-by-model.
  • HTML5lib support if Rails’s HTML parser isn’t doing it for you.

Here’s how you use it.

To install: script/plugin install http://xssterminate.googlecode.com/svn/trunk/xss_terminate

Strip HTML tags from all the fields in a model

1
2
class Article < ActiveRecord::Base
end

Done. All models have tags stripped by default.

Sanitize HTML from some fields

1
2
3
class Article < ActiveRecord::Base
  xss_terminate :sanitize => [:body]
end

Use HTML5lib to sanitize HTML from some fields

HTML5lib is a new library for parsing HTML for Python and Ruby. Its goal is to parse HTML like browsers do, so it’s very fault-tolerant. If you want to use it, gem install html5 and use the :html5lib_sanitize option. This is thanks to code by Jacques Distler.

1
2
3
class Article < ActiveRecord::Base
  xss_terminate :html5lib_sanitize => [:body]
end

But I don’t want to strip HTML at all from that field!

1
2
3
class Article < ActiveRecord::Base
  xss_terminate :except => [:title, :body]
end

Putting it all together

And of course, you can put these options together. Remember, fields are stripped of tags by default, so that’s assumed unless you override it.

1
2
3
class Article
  xss_terminate :except => [:author_name], :sanitize => [:title], :html5lib_sanitize => [:body]
end

Report bugs at the xss_terminate Google Code site.

Extra credit: Use Erubis

Erubis catches 80% of HTML escaping screw ups by making them impossible. You can use it in conjunction with xss_terminate or other XSS plugins to give yourself an extra layer of protection. (See our post on setting up Erubis with Rails 2.0.)

With Erubis, code like <%= "<script>alert('pwnd')</script>" %> can be auto-escaped.

However, all Rails helpers which generate HTML must be called with <%== %> so the HTML is not escaped. This leaves an opening for attacks like this:

<%== link_to user.name, "/some/url" %>

If user.name contains XSS you’re pwnd.

So while Erubis is a marked improvement over Erb it’s not a cure-all. That’s why I like to use both approaches.

Other approaches

There’s been a lot of discussion about Rails and XSS lately, so I’m hopeful that the situation will get better. Here’s a couple other XSS protection projects you can check out:

  • SafeERB – Throws exceptions if you try to display tainted strings. Call h() to untaint.
  • xss-shield – automatically h() strings unless marked as “safe”.
  • sanitize_params – strip HTML from your parameters before they hit your models.
  • AntiSamy – another whitelist-based approach (not available for Rails)

Also, check out Is your Rails App XSS Safe? and Never Untaint by Stu Halloway and Jacques Distler’s posts about making Instiki XSS-safe: XSS and XSS 2 (these are must read).

Bringing the Rails Magic to Facebook

Posted by Eric Chapweske
on Friday, November 02

While there’s a few plugin options for the Rubyist looking to write a Facebook application, none of them quite fit our needs. I opted to write one for internal use at Slantwise. Why? A fundemental difference between this code and the publicly available solutions is that its Rails-centric.

If you’re not planning on writing your app in Rails, this isn’t the library for you. The benefits to the Rails programmer is that they now have a Facebook interface that’s borderline indisguishable from other Rails code—meaning its understandable, enjoyable, and doesn’t require hours of pouring through Facebook’s API documentation.

Ruby, where art thou?

This first sample shows some of the library’s low-level functionality, and its pretty similiar to the other solutions out there. It also demonstrates the inherent problems with simply wrapping API calls.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  # Retrieves photos from the first album that's found for the current user on Facebook
  # Then publishes some of the photos as a news update in Facebook
  ...
  #Retrieve the photos
  recommended_album   = Facebook::API::Albums.get(:uid => current_user.facebook_uid).first
  @recommended_photos = Facebook::API::Photos.get(:aid => album[:aid])

  # Assign all the necessary API params for publishing to Facebook.
  # This is a more complex (and abbreviated) API call
  # A typical update call will take at least a few lines of code
  feed_body_template = render_to_string(:partial => 'facebook/_body_template')
  feed_body_general  = render_to_string(:partial => 'facebook/_body_general')
  ...
  recommended_photos_feed = { :actor => current_user.facebook_uid, 
                              :body_template => body_template,
                              :body_general   => ... ,
                              ... }
  
  #Publish the feed to Facebook
  Facebook::API::Feed.publish_templatized_action @recommended_photos_feed

Direct API calls are great in some instances, but not in most. Writing something like the following could easily take someone new to the Facebook API hours to figure out. It also takes the magic out of working in Rails—increasing development time and developer frustration and ultimately resulting in a lesser product. Let’s bring that magic back and put a smile on our developer’s face while we’re at it:

Hello, old friend

1
2
3
4
5
  
  recommended_album   = current_user.facebook.albums.find_by_name 'Halloween'
  @recommended_photos = recommended_album.photos

  update_facebook 'recommended_photos.feed'

The first line of code is a Facebook API call. It utilizes a basic ActiveRecord connection that’s adapted to run through the Facebook API, so the results behave exactly the same as any other ActiveRecord request.

The update_facebook method is a specialized version of render that looks for a template named ‘recommended_photos.feed’, fills it with data, and sends it to Facebook. In this case, the ’.feed’ extension maps to the Facebook API call Feed.publishTemplatizedActionOfUser. The rendering action is easily configurable to support any extension/API call combination.

Interested?

The plan is to release a development version of the plugin within the next week or two to iron out any glaring bugs, followed very shortly thereafter with a production version that you can freely use in your projects. I’ll announce the plugin release here when it’s available.

Get Involved

While I think I’m off to a good start, I’m looking for help. I’m on the look out for highly useful features. If you’re developing a Facebook application and have any problem areas, send me an example of some problem code and I’ll look into incorporating a solution into the plugin.

Using the UrlKey plugin for pretty, unique URLs

Posted by Luke Francl
on Tuesday, May 15

I really like “pretty” or human-friendly URLs. One way to get them with Rails is to use Rick Olson’s PermalinkFu plugin. PermalinkFu takes care of making a field in your model URL-safe. It escapes non-ASCII characters, removes illegal characters (like ? and /), turns spaces into dashes, and then takes the whole string to lower case.

PermalinkFu is great, but we found it didn’t meet our needs for Better Together.

There are two problems with PermalinkFu. First, it re-creates the permalink every time you save the record, making it not very permanent. Second, the permalinks are not globally unique, so they need to be scoped in some way. This isn’t a problem with blogging engines (with a URL scheme like /2007/05/15/slug how much uniqueness do you need?), but we needed something that would create globally unique permalinks which we could use as lookup keys.

So we wrote the UrlKey plugin to address those needs.

UrlKey takes the same approach to URL-ifying a string as PermalinkFu, but it also ensures that the key is globally unique by appending a number before saving it. It also only sets the key when you create a new record, so if the name changes, the key will not.

Using UrlKey

First, install the plugin:

script/plugin install svn://rubyforge.org/var/svn/slantwise/url_key/trunk

Then create a migration for the model you want to give a unique, human-friendly identifier. By default, UrlKey will look for a column called url_key, but you can call it whatever you want.

1
2
3
4
5
6
7
8
9
10
class AddUrlKey < ActiveRecord::Migration
  def self.up
    add_column :games, :url_key, :string
    add_index :games, :url_key
  end

  def self.down
    remove_column :games, :url_key
  end
end

(This code is from a fun little app we’re working on. Keep your eyes peeled: it launches at RailsConf.)

You’re going to want an index on the key column because it will be used in lookup queries.

To your model, add the has_url_key class method and create a to_param method:

1
2
3
4
5
6
7
class Game < ActiveRecord::Base
  has_url_key :name
  
  def to_param
    url_key
  end
end

The to_param is used by Rails in URL generation. Usually it returns the ID of the object. By changing it to return the url_key, we’ll generate friendly URLs automatically.

But since we’re overriding to_param, we need to make a change to the controller to look up the Game by its url_key:

1
2
3
def show
  @game = Game.find_by_url_key(params[:id]) || Game.find(params[:id]) 
end

Now the GamesController will first look for the Game instance by key, and then by ID. That way any old URLs will still work, and you can use IDs if you want to.

Caveats

UrlKey may not be for everyone.

The uniqueness check will run a query for each iteration until it finds a unique name, so if you have a lot of data this will suck.

Right now, there’s intentionally no facility for re-naming a URL key. It might be a nice feature if combined with a 302 redirect from the old URL.

Other approaches

There are several other plugins that accomplish similar tasks.

PermalinkFu (noted above) is probably the most widely-used.

Others automate the common technique of using the ID in the URL, followed by a slug (for example: /articles/849-my-title-here). Obie Fernandez explains this approach. Two plugins to accomplish this are ActsAsSluggable and Friendly Param. I think these URLs look ugly, but they are easy to create with Rails.

Simplify your ActionMailer configuration with YAML

Posted by Jon
on Friday, March 23

Ruby on Rails looks for your outgoing email settings in a hash in your environment files, like this:

1
2
3
4
5
6
7
8
ActionMailer::Base.server_settings = {
  :address => "mail.domain.com",
  :port => 25,
  :domain => "mail.domain.com",
  :user_name => "email_account_login",
  :password => "email_account_password",
  :authentication => :login
}

This isn’t exactly the cleanest way to configure your SMTP settings, and if you want different settings for your development and production environments, you’ll need to define these settings in two different files (environments/development.rb and environments/production.rb). This means that there is more than one place that your SMTP configuration could be. Not very Rails-like.

Our yaml_mail_config plugin allows you to define your SMTP settings just like your database settings, with a clean, readable email.yml config file.

Install the plugin like this:

script/plugin install \ 
svn://rubyforge.org/var/svn/slantwise/yaml_mail_config/trunk yaml_mail_config

After that, all you have to do is create a config/email.yml file that defines your ActionMailer settings. Here is an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 development:
    server: mail.domain.com
    port: 25
    domain: domain.com
    authentication: login
    username: email_account_login
    password: email_account_password
  production:
    server: mail.domain.com
    port: 465
    domain: domain.com
    authentication: login
    username: email_account_login
    password: email_account_password
    tls: true

Thanks to Sebastien Grosjean for his post which inspired this plugin – the idea and most of the code are his.

Plugin Apocalypse

Posted by Luke Francl
on Friday, March 16

In the most common sense we use it now, “apocalypse” means the end of the world. But originally, it meant a revelation—and that’s the sense I use it now.

Because Slantwise is pleased unveil a few of our internally developed Rails plugins as open source.

  • refresh_to—a Ruby on Rails plugin that adds a refresh_to method to ActionController::Base, allowing developers to avoid Internet Explorer security warnings when moving from a secure page to an insecure page.
  • YAML mail config—extract your SMTP server configuration into a YAML file to avoid error-prone repetition.
  • acts_as_selectable—provides a to_select_form method for your ActiveRecord classes that maps to the Rails select form helper format.
  • acts_as_invitation—easily integrate a “send to a friend” feature to an existing ActiveRecord model.
  • url_key—create never-changing URL ‘slugs’ for permalinks based on attributes in your model.

All these are released under the MIT License, the same license as Rails.