Securely store passwords with bcrypt-ruby; now compatible with JRuby and Ruby 1.9

By Hongli Lai August 13th, 2009

When writing web applications, or any application for that manner, any passwords should be stored securely. As a rule of thumb, one should never store passwords as clear text in the database for the following reasons:

  • If the database ever gets leaked out, then all accounts are compromised until every single user resets his password. Imagine that you’re an MMORPG developer; leaking out the database with clear text passwords allows the attacker to delete every player’s characters.
  • Many people use the same password for multiple sites. Imagine that the password stored in your database is also used for the user’s online banking account. Even if the database does not get leaked out, the password is still visible to the system administrator; this can be a privacy breach.

There are several “obvious” alternatives, which aren’t quite secure enough:

Storing passwords as MD5/SHA1/$FAVORITE_ALGORITHM hashes
These days MD5 can be brute-force cracked with relatively little effort. SHA1, SHA2 and other algorithms are harder to brute-force, but the attacker can still crack these hashes by using rainbow tables: precomputed tables of hashes with which the attacker can look up the input for a hash with relative ease. This rainbow table does not have to be very large: it just has to contain words from the dictionary, because many people use dictionary words as passwords.

Using plain hashes also makes it possible for an attacker to determine whether two users have the same password.

Encrypting the password
This is not a good idea because if the attacker was able to steal the database, then there’s a possibility that he’s able to steal the key file as well. Plus, the system administrator is able to read everybody’s passwords, unless he’s restricted access to either the key file or the database.

The solution is to store passwords as salted hashes. One calculates a salted hash as follows:

salted_hash = hashing_algorithm(salt + cleartext_password)

Here, salt is a random string. After calculating the salted hash, one should store the salted hash in the database, along with the (cleartext) salt. It is not necessary to keep the salt secret or to obfuscate it.

When a user logs in, one can verify his password by re-computing the salted hash and comparing it with the salted hash in the database:

salted_hash = hashing_algorithm(salt_from_database + user_provided_password)
if (salted_hash == salted_hash_from_database):
    user is logged in
else:
    password incorrect

The usage of the salt forces the attacker to either brute-force the hash or to use a ridiculously large rainbow table. In case of the latter, the sheer size of the required rainbow table can make it unpractical to generate. The larger the salt, the more difficult it becomes for the cracker to use rainbow tables.

However, even with salting, one should still not use SHA1, SHA2, Whirlpool or most other hashing algorithms because these algorithms are designed to be fast. Although brute forcing SHA2 and Whirlpool is hard, it’s still possible given sufficient resources. Instead, one should pick a hashing algorithm that’s designed to be slow so that brute forcing becomes unfeasible. Bcrypt is such a slow hashing algorithm. A speed comparison on a MacBook Pro with 2 Ghz Intel Core 2 Duo:

  • SHA-1: 118600 hashes per second.
  • Bcrypt (with cost = 10): 7.7 hashes per second.

Theoretically it would take 4*10^35 years for a single MacBook Pro core to crack an SHA-1 hash, assuming that the attacker does not harness any weaknesses in SHA-1. To crack a bcrypt hash one would need 6*10^39 years, or 10000 more times. Therefore, we recommend the use of bcrypt to store passwords securely.

There’s even a nice Ruby implementation of this algorithm: bcrypt-ruby! Up until recently, bcrypt-ruby was only available for MRI (“Matz Ruby Interpreter”, the C implementation that most people use). However, we’ve made it compatible with JRuby! The code can be found in our fork at Github. The current version also has issues with Ruby 1.9, which we’ve fixed as well. The author of bcrypt-ruby has already accepted our changes and will soon release a new version with JRuby and Ruby 1.9 support.

Ruby, Software | Comments (30)

Getting ready for Ruby 1.9.1

By Hongli Lai February 2nd, 2009

We are excited about Ruby 1.9.1. Of course, with all the performance improvements, who wouldn’t be? Unfortunately a large number of Ruby libraries and extensions still don’t work on 1.9.1, so Ruby 1.9 cannot be considered production-ready yet. Ryan Bigg has done an excellent job on documenting most of the problems that one would encounter when trying to get a basic Rails app up-and-running on Ruby 1.9.1. Basically, the problems he countered were:

  • 2.2.2 isn’t compatible with 1.9.1. Use Rails 2.3.0 RC1 or Rails edge.
  • The mysql gem needs patching.
  • The hpricot gem needs patching.
  • The postgres gem needs patching.
  • Thin needs patching.
  • The fastthread gem needs patching.
  • Mongrel needs patching.

But what about Phusion Passenger? Good news:
Phusion Passenger is Ruby 1.9.1-compatible since this commit (today).

Here’s a screenshot of a Rails 2.3.0 app running in Phusion Passenger on Ruby 1.9.1:

passenger-ruby19

Do you see the changes? Me neither. That’s the point. :)

We’ve encountered the following issues upon trying to get a simple Rails 2.3 app up running with Phusion Passenger and Ruby 1.9.1:

Fastthread isn’t compatible with 1.9
Both Mongrel and Phusion Passenger depend on Fastthread, which is a threading library that fixes some threading implementation bugs in older versions of Ruby 1.8. Fastthread is only a required dependency when running on older versions of Ruby 1.8. Unfortunately there’s no way to tell RubyGems “we depend on fastthread, but only when running on older versions of Ruby 1.8, and not on JRuby”.

Fastthread doesn’t compile on Ruby 1.9 (or on JRuby or other Ruby implementations for that matter), so when you type “gem install passenger” or “gem install mongrel” on Ruby 1.9, the installation fails with a ton of compile errors.

We’ve patched fastthread so that it becomes a no-op on Ruby 1.9.1 and on JRuby (that is, fastthread will install correctly but it won’t do anything). These patches have been submitted to Mentalguy, the maintainer of fastthread.

The sqlite3-ruby gem doesn’t work on 1.9
Jeremy Kemper submitted a 1.9 compatibility patch in the past, which had been committed. Unfortunately even with this patch, sqlite3-ruby isn’t compatible with 1.9.1.

We’ve gone ahead and fixed 1.9.1 support. The patch can be found here: http://rubyforge.org/tracker/index.php?func=detail&aid=23792&group_id=254&atid=1045

Hongli Lai Ninh Bui

Phusion Passenger, Ruby | Comments (26)

Passing environment variables to Ruby from Phusion Passenger

By Hongli Lai December 16th, 2008

Phusion Passenger manages Ruby/Rails process automatically. Sometimes it is necessary set environment variables or to pass environment variables to the Ruby interpreter. This particular aspect of Phusion Passenger isn’t very well documented, so it’s time for a blog post.

Environment variables that may be set after Ruby is started

Some environment variables may be set before or after Ruby is started. These include:

PATH
The search path for binaries.
LD_LIBRARY_PATH
The search path for shared libraries.

It really doesn’t matter where these environment variables are set, as long as you set them before you use them. These variables may be set in environment.rb.

Setting PATH, LD_LIBRARY_PATH and similar variables

Suppose that your environment.rb runs the program “frobnicate”, and this program is located in /opt/frobnicator/bin, which is not in PATH by default. Furthermore, the “frobnicate” program requires shared libraries which are located in /opt/awesome_runtime/lib. Your environment.rb current looks like this:

...
Rails::Initializer.run do |config|
  ...
end
...
system("frobnicate")    # => ERROR: command not found

Set PATH just before the system() call so that it can find the program:

ENV['PATH'] = "#{ENV['PATH']}:/opt/frobnicator/bin"
system("frobnicate")    # => ERROR: cannot load libawesome_runtime.so

Now set LD_LIBRARY_PATH so that the program can find its libraries:

ENV['PATH'] = "#{ENV['PATH']}:/opt/frobnicator/bin"
ENV['LD_LIBRARY_PATH'] = "#{ENV['LD_LIBRARY_PATH']}:/opt/awesome_runtime/lib"
system("frobnicate")    # => success!

Setting GEM_PATH, the RubyGems search path

If you’re on a shared host (e.g. Dreamhost) or on some other server for which you do not have root privileges, then you have no choice but to install gems to somewhere inside your home folder. You also need to tell RubyGems to look in there, and that’s what GEM_PATH is for.

Suppose that you’ve installed the gem “ruby-frobnicator” into /home/foobar/my_gems. In your environment.rb you must set GEM_PATH and call Gem.clear_paths just before requiring the gem, like this:

...
Rails::Initializer.run do |config|
  ...
end
...
ENV['GEM_PATH'] = "/home/foobar/my_gems:#{ENV['GEM_PATH']}"
Gem.clear_paths
require 'ruby-frobnicator'    # => it works!

Environment variables that must be set before Ruby is started

Some environment variables must be set before Ruby is started because the Ruby interpreter itself uses them. The RailsBench GC settings environment variables, which are now supported by Ruby Enterprise Edition, are examples of such environment variables.

You can set these environment variables by writing a wrapper script. Recall that Phusion Passenger has a “PassengerRuby” configuration option which typically looks like this:

PassengerRuby /usr/bin/ruby

You can point this to a wrapper script:

PassengerRuby /usr/local/my_ruby_wrapper_script

/usr/local/my_ruby_wrapper_script can set the environment variables prior to executing the real Ruby interpreter:

#!/bin/sh
export RUBY_HEAP_MIN_SLOTS=10000
export RUBY_HEAP_SLOTS_INCREMENT=10000
export RUBY_HEAP_SLOTS_GROWTH_FACTOR=1.8
export RUBY_GC_MALLOC_LIMIT=8000000
export RUBY_HEAP_FREE_MIN=4096
exec "/usr/bin/ruby" "$@"

A few notes for those who are not familiar with writing shell scripts:

  • Make sure you make /usr/local/my_ruby_wrapper_script executable with chmod +x.
  • Make sure that you prepend the “export” keyword to all environment variable setter statements.
  • The last line says “replace the current process with /usr/bin/ruby, and pass all commandline argument that I’ve received to Ruby”. Make sure that $@ is wrapped inside double quotes, otherwise filenames with spaces in them won’t be passed correctly to the Ruby interpreter.

But wait, I’ve already set environment variables in my /etc/bashrc or /etc/profile. Why don’t they work?

If you’ve set environment variables in your /etc/bashrc or /etc/profile, then these environment variables are made available in your shell. However, on most operating systems, Apache is not started from the shell and does not load environment variables defined in bashrc/profile, which is why setting environment variables in /etc/bashrc and /etc/profile usually has no effect on Apache (and by induction, on Passenger and Rails processes).

Final words

This is just a quick blog post which I’ve written after seeing many people asking questions on this subject. This subject deserves proper official documentation, but I haven’t had the time to do it yet. If anybody wants to submit a documentation patch then please feel free to do so. In the long term it would probably be nice if one can pass environment variables to the Ruby interpreter via Apache configuration options, but it’s not a very high priority issue at this moment.

Phusion Passenger, Ruby | Comments (16)

Phusion Passenger (mod_rails) version 1.0.2 released, and more

By Ninh Bui April 29th, 2008

It has been two weeks since the release of Passenger version 1.0.1. More and more people are switching to Passenger, and most are very pleased with the quality of our initial release. :) But in these past 2 weeks, we’ve continued to make improvements to Passenger. So today, we’re happy to announce the release of Passenger version 1.0.2. :D

Hongli Lai Ninh Bui

Featured improvements and changes

100% support for MacOS X’s default Apache

Passenger has always supported MacOS X. This fact is demonstrated in our screencast, created by Ryan Bates on a Mac. However, there was an inconvenience: Passenger was incompatible with the default Apache installation, as provided by OS X. The installer warned about that. As a result, OS X users had to install Apache via MacPorts or by hand.

But no more. Thanks for the help of Weyert de Boer and the people at Fingertips, we’ve been able to track down the problem. Passenger now fully supports MacOS X’s default Apache! There is no need to install Apache via MacPorts anymore. :)

RubyGems-related fixes: Rails < 2.0 is now supported

The Passenger gem specifies Rails 2.0 as a dependency. This seemed to be a good idea at the time: Passenger is to be used in combination with Rails, and we figured that by specifying Rails as a dependency, the user will have one command less to type.

But it turned out that some RubyGems versions will load Rails 2.0 during Passenger’s startup, even though Passenger didn’t explicitly tell RubyGems to do that. As a result, some people were having trouble with using Passenger with Rails < version 2.0. This issue has been fixed.

Memory statistics tool

Some people have attempted to analyze Passenger’s memory usage. But standard tools such as ‘top’ and ‘ps’ don’t always report the correct memory usage.

We’ve provided a tool, passenger-memory-stats, which allows people to easily analyze Passenger’s and Apache’s real memory usage. For example:

$ sudo ./bin/passenger-memory-stats
------------- Apache processes --------------
PID    PPID  Threads  VMSize   Private  Name
---------------------------------------------
5947   1     9        90.6 MB  0.5 MB   /usr/sbin/apache2 -k start
5948   5947  1        18.9 MB  0.7 MB   /usr/sbin/fcgi-pm -k start
6029   5947  1        42.7 MB  0.5 MB   /usr/sbin/apache2 -k start
6030   5947  1        42.7 MB  0.5 MB   /usr/sbin/apache2 -k start
6031   5947  1        42.5 MB  0.3 MB   /usr/sbin/apache2 -k start
6033   5947  1        42.5 MB  0.4 MB   /usr/sbin/apache2 -k start
6034   5947  1        50.5 MB  0.4 MB   /usr/sbin/apache2 -k start
23482  5947  1        82.6 MB  0.4 MB   /usr/sbin/apache2 -k start
### Processes: 8
### Total private dirty RSS: 3.50 MB

--------- Passenger processes ---------
PID    Threads  VMSize   Private  Name
---------------------------------------
6026   1        10.9 MB  4.7 MB   Passenger spawn server
23481  1        26.7 MB  3.0 MB   Passenger FrameworkSpawner: 2.0.2
23791  1        26.8 MB  2.9 MB   Passenger ApplicationSpawner: /var/www/projects/app1-foobar
23793  1        26.9 MB  17.1 MB  Rails: /var/www/projects/app1-foobar
### Processes: 4
### Total private dirty RSS: 27.76 MB

The private dirty RSS field shows the *real* memory usage of processes. Here, we see that all the Apache worker processes only take less than 1 MB memory each. This is a lot less than the 50 MB-ish memory usage as shown in the “VMSize” column (which is what a lot of people think is the real memory usage, but is actually not).

Please note that this tool only works on Linux. Unfortunately other operating systems don’t provide facilities for determining processes’ private dirty RSS.

Improved stability

If the framework spawner server or application spawner crashes, then Passenger 1.0.1 will keep showing error messages until one restarts Apache. Passenger 1.0.2 will automatically restart spawner servers when they crash, thus lowering maintenance burden even more.

Setting ENV['RAILS_ENV'] in environment.rb now works
A bug caused ENV['RAILS_ENV'] in environment.rb to be ignored. This has now been fixed.
Support for custom page caching directories

Page caching was supported by Passenger, but setting a custom (non-standard) page caching directory did not work. This has now been fixed. But please note that Passenger won’t be able to accelerate page cache files in non-standard page caching directories.

Usability and documentation improvements

The community has provided a lot more insight on things that can go wrong. We’ve done our best to document all troubleshooting-related issue into our Users guide. We’ve also adapted some error messages so that users can solve the problem without reading the manual.

Thanks for all the feedback people! :)

Fixed conflicts with system-provided Boost library

Passenger makes use of the Boost C++ library. Its sources are included into the Passenger sources. But if the system already has a different Boost version installed, then the two Boost libraries would conflict with each other, and Passenger would fail to install. We’ve made sure that this doesn’t happen: now, installation will succeed even if there’s already another Boost version installed.

Improved SSL compatibility

There was a problem with SSL hosts, which would only be triggered if “SSLOptions +ExportCertData” is set. This issue has now been fixed.

Improved support for graceful restarts

If you installed Passenger for the first time, then the first graceful Apache restart would not properly initialize Passenger. This issue has now been solved.

There are also a few small improvements and changes that aren’t worth mentioning.

How do I upgrade?

Just install it like you did the first time:

gem install passenger

and

passenger-install-apache2-module

Please don’t forget to copy & paste the Apache config snippet that the installer gives you.

Enterprise Licenses, donations and t-shirts

In many ways, Phusion Passenger (mod_rails) has been an overwhelming success to us, and we’re very grateful for the community support you guys have given us. Also, a lot of companies and individuals have been more than generous in purchasing an Enterprise License for Phusion Passenger (mod_rails). In particular, we’d like to thank all the people who have donated over a certain amount and thought it would only be fitting to send them something concrete as a reminder of this generous act. After giving it a lot of thought, we came with something really shabby (or at least we ‘part-time fashion connoisseurs’ think so ;) ).

To celebrate our first successful open source product launch here at Phusion, we’ve decided to silkscreen-print 100 limited edition Phusion t-shirts, each hand-numbered from 1 to 100. A few of these will go to our friends at Apple, Sun Microsystems and 37 signals, and the remainder of the shirts will go to those who have donated over 200 USD in total (we’ll take care of the shipping fees). Needless to say, these shirts are going to be hot as heck at IT conferences such as Railsconf, as they have been silkscreen-printed by the same people who are responsible for printing the shirts for the uberhip brands Rockwell, Freshcotton and Top Notch. The shirts themselves are super premium t’s which weigh 205gr/m2. To emphasize this even more, we’ve arranged for a photo shoot with a few professional lady models ;) and just like you, we can’t wait to see the result of this. Hopefully, you’ll be able to see the result soon!

An artist’s impression of the Phusion t-shirt

People who haven’t donated yet, or donated less than 200 USD but who want a piece of the t-shirt action as well will get the opportunity to “set this right” in the second (current) and third batch of enterprise licenses by donating the remainder amount to us under the same PayPal account. We’ll try to sort this out then as soon as possible. Needless to say, first come, first serve will be maintained, so if you want a shirt, be sure to act fast as supplies are bound to not last for very long! You probably don’t want to be figuring out that you actually wanted a shirt like this when it’s too late right? ;) Also, we’ve only got a limited amount in each size (especially the sizes small and XXL are likely to run out fast, and not to mention the girlie sized shirts for the ladies).

Lastly, we’re very grateful for all donations, and it is for this reason that we’ll also occasionaly randomly pick a few people from the donation list that haven’t donated over 200 USD for a Phusion t-shirt as well ;-) . So in short, whatever amount you decide to donate, be sure to include your shirt size as well from now on as it might be your lucky day ;-)

RailsConf

Not only community wise, but also commercial wise, Phusion Passenger has opened up a lot of doors for Phusion that would otherwise likely have remained closed. For starters, we’ll be talking at Railsconf in a little more than a month about Phusion Passenger and the highly anticipated Ruby Enterprise Edition. It seems that the latter has already generated a lot of buzz and that this for the greater part, is because of its name. We actually think this is a good thing since we don’t believe that there is such a thing as bad publicity. ;) Don’t worry too much about it though, Railsconf will provide us with the perfect opportunity to dive into this subject a little bit deeper and hopefully, you’ll agree with us on that it’ll make a lot of sense to call it Ruby Enterprise Edition. We’ll also do something that is probably unprecedented with regards to talks so be sure to check us out over there, even if it’s just for the meet and greet / casual chat. ;)

We’re on the RailsConf speakers list!

Side notes

We’re also still hard at work on writing a series of articles on both Phusion Passenger as well as Ruby Enterprise Edition from which we’ll also distill a scientific paper to be published on eeprints at the University of Twente (rocking! ;-) ). Needless to say, these articles will be published for your reading pleasure as well. ;)

As you may have already noticed, Phusion recently consisted of mainly Hongli Lai and Ninh Bui. Even though we two make up for one hell of a team, we both definitely started feeling the growth pains of a healthy growing startup company. A little while ago we posted some job openings in the hopes of increasing Phusion’s capacity, but unfortunately, most of these applications were from outside of the Netherlands.

Today however, we’re pleased to announce that our good friend Tinco Andringa has decided to join the fray by joining Phusion. He’s not alone in this though, since our other good friend Maurits Dijkstra has also decided to do the same. And yes, the latter of the two IS related to the famous Edsger Dijkstra, which you may already know from Dijkstra’s shortest path algorithm ;) (but that wasn’t the main reason why we wanted him on board at Phusion per se ;) ) Just like with Hongli and I, Maurits’ and Tinco’s computer science education find their origin at the Universiteit Twente and both have built a nice career on the side as software engineers as well: with this configuration, we hope to be able to even deliver better on our services and products!

Well, that wraps it up for today! Stay tuned though, as we’ve only started to ‘bring it on’! ;)

With kind regards, your friends at Phusion,

Hongli Lai Ninh Bui

- Tinco Andringa
- Maurits Dijkstra

Phusion Passenger, Ruby, Ruby on Rails | Comments (11)