Taking Password Storage Up A Notch

Taking Password Storage Up A Notch

Adam Gooch
Adam Gooch

November 04, 2012

Protect your users, take password management seriously.

There are too many databases in the world with completely unencrypted passwords. Even when databases have encrypted passwords, they typically do not implement protection that is strong enough to keep them from being stolen, and used maliciously. With the advancements in computing technology, we now need another approach to store passwords and keep them safe from prying eyes. Fortunately, you don't have to be a cryptography expert to use good password protection.

Passwords that are only hashed once are vulnerable to brute force, dictionary attacks, and rainbow tables. To combat these attacks, salt has been added to hashed passwords. However, with growing computing power, we need to go one step further. To protect our users properly, we need to increase the time it takes to encrypt passwords.

Two examples of alternate methods for password storage that solve the time problem are PBKDF2 and BCrypt. PBKDF2 stands for password based key derivation function 2. It is a replacement for an older function and is most notably used by iOS, Android, and LastPass. BCrypt is a technology used on secure operating systems such as OpenBSD. Here are the different implementations in Rails. First, the wrong way.

Plain Text (The Wrong Way)

Here is what a normal Rails model might look like without password encryption. All of the logic is in the controller to keep things simple and get the point accross.

1class User < ActiveRecord::Base
2 attr_accessible :email, :password, :password_confirmation

And this is what a normal Rails controller could look like without password encryption. The fields in the table are email, and password_digest.

 1class UsersController < ApplicationController
 2 def index
 3 end
 5 def new
 6 @user = User.new
 7 end
 9 def create
10 @user = User.new
11 @user.email = params[:user][:email]
12 @user.password_digest = params[:user][:password]
13 if @user.save
14 redirect_to @user
15 else
16 render :new
17 end
18 end
20 def show
21 @user = User.find(params[:id])
22 end
24 def authenticate
25 user = User.find_by_email(params[:email])
26 if user && user.password_digest == params[:password]
27 redirect_to user
28 else
29 render :index
30 end
31 end

Now let’s see what these would look like with enhanced encryption methods and find out how easy it is to add additional security to your application.


For Rails users, there is a gem called pbkdf2 available that will get you started right away. Put it in your Gemfile and run bundle install. In your user table, ensure you have fields for username, derived key, and salt.

Salt is a randomly generated set of bytes that is appended to an encrypted password. This is done to protect against rainbow table attacks. When a new user creates an account, generate a unique salt for that user. After the salt has been generated, a key can be derived with the user’s password.

The PBKDF2 model is the same as it would be in a clear text implementation.

1class User < ActiveRecord::Base
2 attr_accessible :email, :password, :password_confirmation

The controller, on the other hand, has a few differences.

 1require 'pbkdf2'
 3class UsersController < ApplicationController
 4 def index
 5 end
 7 def new
 8 @user = User.new
 9 end
11 def create
12 @user = User.new
13 @user.email = params[:user][:email]
14 @user.salt = make_salt
15 @user.password_digest = encrypt(params[:user][:password], @user.salt)
16 if @user.save
17 redirect_to @user
18 else
19 render :new
20 end
21 end
23 def show
24 @user = User.find(params[:id])
25 end
27 def authenticate
28 user = User.find_by_email(params[:email])
29 if user && user.password_digest == encrypt(params[:password], user.salt)
30 redirect_to user
31 else
32 render :index
33 end
34 end
36 private
38 def encrypt(clear_text, salt)
39 derived_key = PBKDF2.new do |key|
40 key.password = clear_text
41 key.salt = salt
42 key.iterations = 10000
43 end
44 return derived_key.hex_string
45 end
47 def make_salt
48 return SecureRandom.hex
49 end

The encrypt function will return a string that looks something like this:


Store the result in the derived key field of your user table. The generated salt should be stored in the salt field. Keep in mind that the salt isn't meant to be a secret, so storing it in the same table as the password is okay. It is, however, meant to be unique and randomly generated.

Notice the number of iterations given to the PBKDF2 block. Ten thousand iterations is the current suggested guideline but understand that this can be set to accommodate specific performance needs. As the number of iterations goes up, the processing power required to authenticate users goes up. However, this also increases the time required for each and every password cracking attempt, which is what we want.

To authenticate the user, just run the same function with the salt stored in the table and the password given by the user. If the result matches the derived key that was stored in the table when the account was created, the user is authenticated. Now let’s look at the BCrypt implementation.


The beauty of BCrypt is that Rails 3 does most of the work for you. However, there a few key steps that must be done to use it. First, you need to put bcrypt-ruby in your Gemfile and bundle install it.

Next, you must make sure that a field called password_digest is in your user table with a string type. You'll also need some sort of username field as well, such as an email address. You will not, however, need a salt field. This is an advantage to BCrypt in my opinion.

The next step to utilizing Rails 3's built in BCrypt support is to put has_secure_password in your user model as illustrated below.

1class User < ActiveRecord::Base
2 has_secure_password
4 attr_accessible :email, :password, :password_confirmation

You're now ready to allow users to create accounts. The UsersController would look something like this. Again, you can move the logic to a better place, this is a simple example.

 1class UsersController < ApplicationController
 2 def index
 3 end
 5 def new
 6 @user = User.new
 7 end
 9 def create
10 @user = User.new(params[:user])
11 if @user.save
12 redirect_to @user
13 else
14 render :new
15 end
16 end
18 def show
19 @user = User.find(params[:id])
20 end
22 def authenticate
23 user = User.find_by_email(params[:email])
24 if user.try(:authenticate, params[:password])
25 redirect_to user
26 else
27 render :index
28 end
29 end

When the user has been created, the generated password digest will look something like this:


BCrypt stores the salt along with the derived key together so you don't have to mess with it. The salt is taken care of for you and the digest is stored in a single field in the database. The iteration count is also stored, making this algorithm easily scalable as computational speeds increase.

Wrap Up

As you can see, implementing solid password practices is quick and easy. There is very little extra code added to the plain text version, to get the PBKDF2 or the BCrypt version. While I've focused on Ruby on Rails in these examples, implementations are available for many other languages that are ready to be used. C#, Java, and Python are just a few examples.

Databases full of usernames, emails, and passwords are being stolen at an alarming rate. BCrypt and PBKDF2 are two ways to securely store passwords and protect your users’ identities. Single hashed and salted passwords are not enough any longer. Use one of these methods and begin increasing your iteration count today.