layout: post
title: Timing attack vulnerability in Rails
date_string: 21 February 2016
—
Disclaimer
I am not a security expert and this post is my attempt to learn a bit more about web security.
Why now?
Well, I am signed up to Ruby on Rails security mailing list to make sure vulnerabilities don’t go unnoticed and all my projects are running patched versions. Usually I just read the emails and ensure to upgrade or patch the affected versions and this system has worked very smoothly, however, I have never been happy with this approach and when a timing attack vulnerabilitywas announced on 25th January 2016 (CVE-2015-7576), I decided to research and learn more about it.
What is a timing attack?
A timing attack allows an adversary to learn more about the system under attack by statistically analysing information based on different response times. Here are a few examples:
The size of response for a signed in user and a signed out user will be significantlly different, thus allowing the adversary to determine user’s current state.
A string comparison with no matching characters will be slightly faster than one with 2 matching characters.
There are many more examples along the same lines. One thing worth mentioning is that it takes a lot more analysis and patience for a successful timing attack, but it’s not impossible.
How can we fix the string comparision to run in constant time?
Although, there are several ways to use the timing attack but in the interest of this article the scope is limited to secure string comparison in Ruby. There are two ways to do it:
Activesupport
Activesupport provides a secure_compare method that can be used like this:
def secure_compare(a, b)
return false if a.empty? || b.empty? || a.bytesize != b.bytesize l = a.unpack "C#{a.bytesize}"
res = 0
b.each_byte { |byte| res |= byte ^ l.shift }
res == 0
end
Why no secure compare in Ruby?
You may ask why does Ruby not have a secure compare as part of the core API? I have no idea, but, there has been movement on that front lately and you can follow that discussion in ruby’s bug discussion area. It’s currently waiting for Matz approval.
Research
I don’t want to repeat the research that has been conducted by others, so here’s a review of things I researched and if you’re interested you should read these to gain more understanding.
Tools
Whilst researching I came across the following tools to test for a timing attack. I’ve not tried them myself but give them a go:
Login timing attacks for mischief and mayhem - This is a presentation into the timing attacks but being a persentation with no audio it’s a bit hard to know the intention of the speaker, nonetheless, full of useful information.
Opportunities and Limits of Remote
Timing Attacks - This paper goes into the details of the actual statistical mesaurements required as part of the a successful timing attack. To be honest, I read the beginning
and realised the Maths was too complicated for my simple brain.
Web Timing Attacks Made Practical - Again, very thought provoking yet a bit heavy on the statistical analysis which is an integral part of a timing attack.
The Tagled Web A Guide to Securing Modern Web Applications
The Web Application Hackers Handbook
This research is not comprehensive and I hope its given you enough to carry on this journey by yourself.
Update (17.03.2016)
Good news! Just seen update on the ruby issue and apparently OpenSSL provides a timing safe binary comparison method called
CRYPTO_memcmp which is what will be used in ruby internally and exposed from it to be used by other libraries.
Webpack dev server is pretty awesome. In my last post, I set up React, ES6, Babel and Webpack and the only thing outstanding was the webpack dev server.
With a webpack dev server running, developers can update their code and have the code changes show up straightaway in the browser, thanks to websockets. In order to implement it for a rails application, I did the following:
For development mode, I am downloading the bundle.js from localhost:9999. That’s the port where the webpack dev server is running at. For the production mode, the bundle.js is being read from the `app/assets/javascripts’ directory.
I have the following in my package.json to to run the webpack dev server on port 9999:
This completes the react and webapck setup for a rails application.
One thing to bear in mind, is to create a production ready bundle.js before deploying this application, but that can be part of a capistrano deployment hook.
If you have got two projects using the same functionality, then write a Rubygem to promote code reuse and modularity. Writing a gem is not a new thing. In fact, there are 6,710,940,000 gems and counting, as per the rubygems homepage.
Years ago Jamis Buck said in one of his blogs that if you don’t understand the inner workings of a gem, don’t use it as a dependency. Very fair comment indeed! I’m guilty of using the gems without really knowing their inner workings. To be honest, as a modern day programmer with a constant client expectation to deliver solutions, it’s okay to take your eyes of the ball.
However, I decided to make amendments when it came to integrating a react app into rails. I wanted to learn and fix the issues that comes with integrating and therefore, decided to start it from scratch. If you wish to use, there are a couple of nice integrate react with rails gems out there, namely, react_on_rails and react-rails.
What are we going to do
Recently, I have crossed over to the Javascript world and been doing a lot of React, ES6 (with babel) and webpack and I wanted to use the same ideas in a Rails project.
There are a few things to keep in mind:
A react component will serve as the client talking to the rails as a backend.
The rails will be used a backend.
It’s not an isomorphic application meaning there will be no server-side rendering of react components.
It should play nicely with rails asset pipeline.
As part of this article, we are going to set-up a react app in both development and production-mode that will play nicely with a rails app.
Setting up a rails app
As a seasoned rails developer, I expect you guys to know how to do this.
Setting up a react app
Create a directory called client at the same level as the app.
Create a file called package.json in the client directory. Package.json is to npm what Gemfile is to Bundler. Copy the following contents into the client/package.json. Most of it is pretty self-explanatory except the scripts section. Npm allows you to create these tasks inside the scripts section runnable from the command line via npm run command. Under scripts, start starts a webpack dev server useful for reloading the app whilst working in development. build is for building the app locally and uses the default webpack config and finally, build:prod builds the final distributable js file using webpack’s production config.
Finally, create webpack.production.config.js in the client directory with the following contents. This is mainly used for creating a production ready distributable bundle. It is invoked with a -p option at the command line to trigger automatic minification.
Create a directory called src/js in the client directory.
In the src/js directory, create a file called app.js. This is the entry file for webpack. Entry file is the file webpack uses to workout all the other dependencies that it needs to bundle up in the final distributable file.
The app.js file should have the following contents. This is the entry point for the app. Here it’s rendering the react app in a dom node with the id react-app. Make sure a dom node with the same id exists in the layout file of your rails app, otherwise, react will have no place to mount the app.
import React from 'react'
import ReactDOM from 'react-dom'
import App from './components/App.react'
ReactDOM.render(
<App />,
document.getElementById('react-app')
);
One last thing, create the following directory, src/js/components and in there create a root react component called App.react.js with the following contents. As you can see, the App is written in ES6 classes and takes advantage of the modular dependency provided by ES6 out of the box.
Added it at the bottom of the layout file with a script tag to ensure the DOM node that react app depends upon is there before react’s mounting kicks in.
Opened the rails root page in a browser to check the react app is being mounted correctly and React App (the contents of the App.react.js component) is being rendered on the page.
Phew, further investigation things!
Firstly, you will see there is an error in the dev tools. The app still works fine. This means the at the time of the mount react didn’t find the DOM node which seems bizzare because it works fine. I noticed removing the line of code that brings in application.js in your rails layout file fixes this issue.
Uncaught Error: Invariant Violation: _registerComponent(...): Target container is not a DOM element.
You will also notice a lot of sock.js errors in the dev tools. This is because the in the webpack development config we’ve set it up to communicate with the local webpack dev server and update any changes to the app via websocket. I haven’t quite worked out how the webpack-dev-server communication with this will work, so ignore those for now, or just build the bundle.js using webpack production config.
And, that’s it!
Update: 06 December 2015
The following error
Uncaught Error: Invariant Violation: _registerComponent(...): Target container is not a DOM element.
is my fault. In my app/assets/javascripts/application.js, I had the line to include the bundle.js file and since this file is brought into the layout in the head section - when the DOM node that react app needs is not ready - it throws an error. We use bundle.js as a precompiled asset, so we don’t need to bring it in as part of appication.js. There’s an easy fix in Sprockets for it. If you would like to ignore a file in your directory you use the stub call. So, my application.js file now looks like:
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require_tree .
//= stub bundle
Novelty of writing a gem has worn off. Back in the days when Rails had
just come out, writing a gem (or a plugin) was an achievement in itself.
What has a gem got to do with Rails? You write ruby gems and rails is
just another gem, no?
Correct!
It has nothing to do with Rails but my Ruby adventure began with Rails
and I for one give the credit where it’s due, without a shadow of doubt.
History
Anyways, around 4 years ago, I created a gem called is_bot. It offers some spam protection for web forms. I can’t even remember the project I used it on back then.
However, recently we’ve been marketing Suggestion.io and encountered a lot of spam sign ups and decided to fix the issue.
Why not just use a captcha?
I hate asking prospective clients to fill in yet another field. You want
to make it easier not difficult to sign up. is_bot is different. It just
adds a invisible text field making it hidden from the actual users. Time
to get one back on the damn bots!
Why reboot? Why not use a Rails 4 gem?
I looked at few existing gems but none worked nicely. It was time to
reboot is_bot. Back then it was written for Rails 3 so had to upgrade it
for Rails 4 APIs which was a bit of a pain since it’s hard to find what
changed from Rails 3 to Rails 4, easily. Reading through Rails source
code and looking at some of the other gems got us through.
Technology is flying…
I also took this opportunity to change a few more things…I say a few,
but so much has changed, hasn’t it?
Replaced Jeweler with Bundler as a gem to manage my ruby gem. Just
find it easier to use.
Started using semantic versioning. Makes perfect sense for open source project.
Upgraded to latest RSpec.
Replaced .rvmrc to .ruby-gemset and .ruby-version.
It was a bit of a work, but in the end all the efforts paid off.
There are several ways of adding a method to a ruby class (or instance),
for example, define_method, method_missing, or by just opening up the
class itself.
However, can we remove the methods from a Ruby class?
I encountered two ways of removing methods from a class:
There are subtle differences between the two. The former removes the
method from the current class, where as the latter, stops responding to
the methods in the current class.
Let’s look at an example for the same. Imagine we have a parent class,
Appliance (a.k.a Kitchen Appliance), and child class, Can opener. Here
are the definitions for the two classes:
class Appliance
def name
puts "I'm a kitchen appliance"
end
end
class CanOpener < Appliance
def name
puts "I'm a can opener"
end
end
Now, let’s try remove_method and see what happens.
can_opener = CanOpener.new
can_opener.name
class CanOpener
remove_method :name
end
can_opener.name
puts "Can Opener has a name? #{can_opener.respond_to?(:name)}"
This will produce the following output:
I'm a can opener
I'm a kitchen appliance
Can Opener has a name? true
As soon as you remove a method from a class it treats the method as
undefined and goes up the ancestor chain to look for an implementation,
which it finds in the parent class. Since, there’s an implementation
respond_to returns true.
However, undef_method works slightly differently and let’s see how:
class Appliance
def name
puts "I'm a kitchen appliance"
end
end
class CanOpener < Appliance
def name
puts "I'm a can opener"
end
end
can_opener = CanOpener.new
can_opener.name
class CanOpener
undef_method :name
end
puts "Can Opener has a name? #{can_opener.respond_to?(:name)}"
can_opener.name
This will produce the following output:
I'm a can opener
Can Opener has a name? true
/tmp/execpad-f7201e261f52/source-f7201e261f52:21:in `<main>': undefined method `name' for #<CanOpener:0x41017dcc> (NoMethodError)
Unlike remove_method, undef_method stops responding to the method
and doesn’t travel up the ancestor chain. It totally disregards the
method implementation in the parent class.
Quite interesting, however, I’ve never seen it used in any of the
production code before, so, hopefully, I will find a good use case for
it soon.