Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I program defensively in Ruby?

Here's a perfect example of the problem: Classifier gem breaks Rails.

** Original question: **

One thing that concerns me as a security professional is that Ruby doesn't have a parallel of Java's package-privacy. That is, this isn't valid Ruby:

public module Foo
  public module Bar
    # factory method for new Bar implementations
    def self.new(...)
      SimpleBarImplementation.new(...)
    end
    def baz
      raise NotImplementedError.new('Implementing Classes MUST redefine #baz')
    end
  end

  private class SimpleBarImplementation
    include Bar
    def baz
      ...
    end
  end
end

It'd be really nice to be able to prevent monkey-patching of Foo::BarImpl. That way, people who rely on the library know that nobody has messed with it. Imagine if somebody changed the implementation of MD5 or SHA1 on you! I can call freeze on these classes, but I have to do it on a class-by-class basis, and other scripts might modify them before I finish securing my application if I'm not very careful about load order.

Java provides lots of other tools for defensive programming, many of which are not possible in Ruby. (See Josh Bloch's book for a good list.) Is this really a concern? Should I just stop complaining and use Ruby for lightweight things and not hope for "enterprise-ready" solutions?

(And no, core classes are not frozen by default in Ruby. See below:)

require 'md5'
# => true
MD5.frozen?
# => false
like image 614
James A. Rosen Avatar asked Aug 28 '08 14:08

James A. Rosen


1 Answers

I don't think this is a concern.

Yes, the mythical "somebody" can replace the implementation of MD5 with something insecure. But in order to do that, the mythical somebody must actually be able to get his code into the Ruby process. And if he can do that, then he presumably could also inject his code into a Java process and e.g. rewrite the bytecode for the MD5 operation. Or just intercept the keypresses and not actually bother with fiddling with the cryptography code at all.

One of the typical concerns is: I'm writing this awesome library, which is supposed to be used like so:

require 'awesome'
# Do something awesome.

But what if someone uses it like so:

require 'evil_cracker_lib_from_russian_pr0n_site'
# Overrides crypto functions and sends all data to mafia
require 'awesome'
# Now everything is insecure because awesome lib uses 
# cracker lib instead of builtin

And the simple solution is: don't do that! Educate your users that they shouldn't run untrusted code they downloaded from obscure sources in their security critical applications. And if they do, they probably deserve it.

To come back to your Java example: it's true that in Java you can make your crypto code private and final and what not. However, someone can still replace your crypto implementation! In fact, someone actually did: many open-source Java implementations use OpenSSL to implement their cryptographic routines. And, as you probably know, Debian shipped with a broken, insecure version of OpenSSL for years. So, all Java programs running on Debian for the past couple of years actually did run with insecure crypto!

like image 179
Jörg W Mittag Avatar answered Sep 28 '22 19:09

Jörg W Mittag