Josh Lane Code that I felt like sharing

Sinatra ERB XSS escaping

While Rails escapes HTML by default, Sinatra requires some handholding to produce a similar protection. The following describes two simple solutions.

Setup

Given a basic Sinatra application

# lib/app.rb
class App < Sinatra::Base
  get '/users' do
    @users = User.all

    erb :users
  end
end

and a corresponding ERB template

<%# lib/views/users.erb %>
<% @users.each do |user| %>
  <tr>
    <td><%= user.id %></td>
    <td><%= user.name %></td>
  </tr>
<% end %>

any user-defined input will show the unescaped value. This setup is immediately vulnerable to persistent XSS attacks. For instance, a User with a name like <script src=http://www.example.com/malicious-code.js></script> will appear as:

<tr>
  <td>1</td>
  <td><script src=http://www.example.com/malicious-code.js></script></td>
</tr>

Offensive solution

Use ERB::Util#h on the specific inputs that should be escaped.

  • include ERB::Util
# lib/app.rb
class App < Sinatra::Base
  include ERB::Util
end
  • Explicitly escape desired inputs
-    <td><%= user.id %></td>
+    <td><%= h user.name %></td>

This produces the desired result of:

<tr>
  <td>1</td>
  <td>&lt;script src=http://www.example.com/malicious-code.js&gt;</script></td>
</tr>

While this solution is very simple, if a developer forgets to escape a value the site becomes vulnerable.

Defensive solution

Assume all inputs are possible sources of attack and escape by default.

  • Add erubis to your Gemfile
gem 'erubis'
  • Add escape_html ERB setting in Sinatra
class App < Sinatra::Base
  set :erb, { escape_html: true }
end

This produces the desired result of:

<tr>
  <td>1</td>
  <td>&lt;script src=http://www.example.com/malicious-code.js&gt;</script></td>
</tr>

without alterations to the ERB file.

Note: There are a few cases when you absolutely do not want to render inputs as escaped. In order to get raw inputs use ==.

  • With a yield in a layout
# lib/views/layouts/application.erb
<body>
  <%== yield %>
</body>
  • Partial templates
<% users.each do |user| %>
  <%== erb ':user/show', user: user %>
<% end %>

Automatic database migration for happiness

So I find this little bastard in Rails ~> 4.0.0 wicked annoying.

ActiveRecord::Migration.check_pending!

Except, I get it. It’s not up to Rails to decide if you want run your migrations or not.

Sometimes you are working on tests, and you have a pending migration but you don’t want it to run yet. What I do dislike is checking out some updates, running tests and then immediately failing. DataMapper is especially anal about this because of the relationship integrity checks.

My solution is to sprinkle this little snippet around:

Rails.application.config.after_initialize do
  needs_migration = begin
                      ActiveRecord::Migrator.needs_migration?(ActiveRecord::Base.connection)
                    rescue ActiveRecord::NoDatabaseError
                      true
                    end
  # migrate database if migration file isn't run but is in version control
  pending_migration = (Dir["db/migrate/*.rb"] - `git ls-files db/migrate/*.rb`.split($\)).empty?

  if !ENV["NO_MIGRATE"] && %w[development test].include?(Rails.env) &&
      needs_migration && pending_migration
    ActiveRecord::Tasks::DatabaseTasks.create_current
    ActiveRecord::Migrator.up(ActiveRecord::Tasks::DatabaseTasks.migrations_paths)
  end
end

The real clutch piece here is that having a migration checked into git effectively means it’s ready for party time.

The gating of the development and test environment is important because you probably don’t want your database migrations to run as a side effect of booting your app in production.

I usually stuff this in config/application.rb but you could just as easily but it in a config/initializer/auto_migrate.rb file.

Happy auto migrating!

Lazy pinky workarounds

I have a tendency to keep my right pinky down on the shift key when typing : to enter vim command mode. This causes my command to start with a capital letter, which is rarely useful. Besides focusing more on lifting it up more quickly I have configured vim to figure out what my intentions really are.

My most commonly misspelled commands are:

  • :Wa which is intended to be :wa - write all files
  • :W which is intended to be :w - write current buffer
  • :E which is intended to be :e - open a file

I’ve remapped the previous errored commands to be their intended targets by adding

to my ~/.vimrc

If you find this useful, all my dotfiles are public

convert to 1.9 hash syntax

I am trying to get used to the new Ruby 1.9 hash syntax (read more). Here’s a quick VIM replace command to convert all the 1.8 syntax to the new 1.9 syntax.

I am quickly becoming a fan of this new style simply because it’s less characters to type and it looks more like JSON.

A similiar regex could be used in conjunction with sed to convert a whole project in one go.