Plough => Ruby Journey through ruby

Timing Attack Ruby Vulnerability


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:

  1. 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.

  2. 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:

ActiveSupport::SecurityUtils.secure_compare(a, b)

Don’t use Activesupport

I took this implementation from Time Trial - Racing Towards Practical Remote Timing Attacks paper and looks similar to activesupport’s implementation.


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:

  • https://github.com/dmayer/time_trial
  • https://github.com/ecbftw/nanown
  • https://github.com/aj-code/TimingIntrusionTool5000

Papers/Articles

Books

  • 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 and Rails

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:

<% if Rails.env.development? %>
  <%= javascript_include_tag 'http://localhost:9999/bundle.js', 'data-turbolinks-track' => true %>
<% else %>
  <%= javascript_include_tag 'bundle', 'data-turbolinks-track' => true %>
<% end %>

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:

{
  "name": "ecommerce-checklist",
  "version": "0.0.1",
  "description": "Ecommerce checklist",
  "scripts": {
    "start": "webpack-dev-server --content-base ../app/assets/javascripts --port 9999",
    "build": "./node_modules/webpack/bin/webpack.js --progress",
    "build:prod": "./node_modules/webpack/bin/webpack.js -p --progress --config webpack.production.config.js"
  },
  "dependencies": {
    "react": "^0.14.2",
    "react-dom": "^0.14.2"
  },
  "devDependencies": {
    "babel-core": "^6.0.20",
    "babel-eslint": "^4.1.5",
    "babel-loader": "^6.0.1",
    "babel-preset-es2015": "^6.0.15",
    "babel-preset-react": "^6.0.15",
    "babel-preset-stage-0": "^6.0.15",
    "eslint": "^1.8.0",
    "eslint-loader": "^1.1.1",
    "eslint-plugin-react": "^3.6.3",
    "html-webpack-plugin": "^1.6.2",
    "react-hot-loader": "^1.3.0",
    "webpack": "^1.12.2",
    "webpack-dev-server": "^1.12.1"
  }
}

Note the bit under scripts -> start.

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.

Integrate React, ES6, Webpack and Babel with Rails

Roll your own

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:

  1. A react component will serve as the client talking to the rails as a backend.
  2. The rails will be used a backend.
  3. It’s not an isomorphic application meaning there will be no server-side rendering of react components.
  4. 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.
{
  "name": "react-app",
  "version": "0.0.1",
  "description": "React App",
  "scripts": {
    "start": "webpack-dev-server --content-base dist/ --port 9999",
    "build": "./node_modules/webpack/bin/webpack.js --progress",
    "build:prod": "./node_modules/webpack/bin/webpack.js -p --progress --config webpack.production.config.js"
  },
  "dependencies": {
    "react": "^0.14.2",
    "react-dom": "^0.14.2"
  },
  "devDependencies": {
    "babel-core": "^6.0.20",
    "babel-eslint": "^4.1.5",
    "babel-loader": "^6.0.1",
    "babel-preset-es2015": "^6.0.15",
    "babel-preset-react": "^6.0.15",
    "babel-preset-stage-0": "^6.0.15",
    "eslint": "^1.8.0",
    "eslint-loader": "^1.1.1",
    "eslint-plugin-react": "^3.6.3",
    "html-webpack-plugin": "^1.6.2",
    "react-hot-loader": "^1.3.0",
    "webpack": "^1.12.2",
    "webpack-dev-server": "^1.12.1"
  }
}
  • Create webpack.base.config.js in the client directory with the following contents:*
var webpack = require('webpack');

module.exports = {
    entry: './src/js/app.js',
    output: {
        path: '../app/assets/javascripts/',
        filename: "bundle.js"
    },
    module: {
        preLoaders: [
            {
                test: /(\.js$)/,
                exclude: /node_modules/,
                loader: "eslint-loader"
            }
        ],
        loaders: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: "babel-loader",
                query: {
                   presets: [ "react", "es2015", "stage-0" ]
                }
            }
        ]
    },
    eslint: {
        configFile: '.eslintrc'
    },
    plugins: [
        new webpack.NoErrorsPlugin()
    ]
}

  • Create webpack.config.js in the client directory with the following contents. This is the default config used by webpack.
var webpack = require('webpack'),
    config = require('./webpack.base.config.js');

config.entry = [
    'webpack-dev-server/client?http://0.0.0.0:9999',
    config.entry
];

config.output = {
    path: config.output.path,
    filename: config.output.filename
};

module.exports = 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.
var webpack = require('webpack'),
    config = require('./webpack.base.config.js');

config.entry = [
    config.entry
];

config.output = {
	path: config.output.path,
    filename: config.output.filename
};

module.exports = config;

  • 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.
import React, { Component, PropTypes } from 'react'

class App extends Component {
    render() {
        return (
            <div>
                <h1>React App</h1>
            </div>
        );
    }
}

export default App

Workflow

  • Open a terminal window and navigate to the client directory that we created above.
  • Run npm run build. This will create a bundle.js (development version) and to app/assets/javascripts directory.
  • Make sure to refer to it from the layout file. I added it to the config/initializers/assets.rb as a precompiled file:
Rails.application.config.assets.precompile += %w( bundle.js )
  • 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

Rebooting an old gem

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.

Removing a method in Ruby

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.