Application Password Best Practice

Best practices for application password encryption

Caption

Note: This article is old and needs to be updated but is reproduced here for history. It doesn't cover API tokens, oAuth2/OpenID, Kerberos etc.

Our Certified Ethical Hacker CEH training course is attended by all types, from system administrators and application developers to cyber security professionals. A common question from developers is how to implement secure passwords in applications when there is no LDAP, Kerberos or Active Directory integration.

This question comes up in the sections of the CEH training covering password cracking techniques, password algorithms and best practice so its appropriate to cover what these are first.

 

Password History

Back-in-the-day it was thought it was enough to merely hash user passwords in a one-way encryption algorithm such as MD5. If the password was revealed, for example via someone getting read access to the password database or via an unencrypted network connection, assuming the password is being transferred encrypted, the perpetrator would not have access to the password.

A lot of protocols and application still use password authentication protocol (PAP) where plain text passwords are passed around until they reach the password database where they are encrypted and then compared to the stored encrypted password for authorisation.

In early versions of Unix, for example, encrypted password were stored in the world-readable /etc/passwd file until they were moved out to the shadow password file readable only by root. It was soon realised that this was not a good idea. The first step is never to let anyone get hold fo the encrypted password :)

Password Encryption

The principle is, given a sound encryption algorithm, the amount of computing time required to crack an encrypted password using that algorithm should makes it infeasible or uneconomic to perform. But, as computing power increases, so the algorithms used to encrypt need to be enhanced or changed to keep the cost curve high enough. Additionally some formally "secure" algorithms are found to have fatal flaws some time after adoption.

MD5, for example, is now considered insecure due to a flaw in the algorithm and as a way has been found to generate collisions, ie the same hash is generated for different input.

SHA1 algorithms are still considered secure but as computing power is increasing it is consider a matter of time (years) before computers are commonly available that can crack a SHA1 password. Everyone is upgrading to SHA2.

"Uncrackable" Encryption Algorithm

So, assuming you have an "uncrackable" algorithm, is it enough for password security? The answer is, of course, no. If someone has an encrypted password they can simply attempt to brute force it. i.e guess the password by trying different combination of characters until they get the matching hash, hence those minimum password requirements.

Even if proper password policies are enforced such as minimum length of 10 characters or more with a combination of upper case and lower case etc password as still vulnerable simply because people will tend to use common combinations of letters and characters, thereby limiting the key space to a size that becomes feasible to crack.

Rainbow Tables

Still brute forcing passwords with a good policy is time consuming. To speed up attacks hash password can be pre-generated and then compared against any encrypted password via lookup to check for a match. This speeds up password "cracking" by orders of magnitude as one no longer needs to laboriously encrypt every combination in the key space and then compare it to the actual password aka brute forcing.

These pre-generated tables of passwords are commonly called rainbow tables and are one of the first things run against a password database once obtain.

Password Salting and Hashing

So even if you force your users to use strange combinations of keys, users will probably use the common special characters of "!","#" and digits and common passwords across applications and services. If I get your password from a service that is less secure I can then simply compare encrypt it with a different algorithm and compare it to another database for a match.

An technique to work around rainbow tables, reused or common passwords, that heightens the cost of cracking is to use what is referred to as a salt. A salt is a random combination of characters used as a prefix or suffix to a user password which is then encrypted and stored. The salt also needs to be stored along with the password otherwise it would not be possible for the algorithm to generated the encrypted password again.

The benefits of this is that rainbow tables cannot be used, forcing the person trying to crack the password back to brute-forcing it. The important point to note is that the salt is kep along with the password so if the database is stolen the perpetrator has access to the salt as well. So they can still brute force passwords but not use rainbow tables. (Unless of course you slat generator has a limited key space too and then they just try and pre-generate all combinations thereof.)

Application Password Best Practice

So to implement a good password scheme for your application you need:

  • A good algorithm, preferably one which can increase cost of computation over time without requiring algorithm changes
  • A good salting generator and a
  • A protocol to store the salt and encrypted password

Bcrypt Algorithm and Password API

The state-of-the-art encryption algorithm for password encryption, that is also easy to use, is the Bcrypt algorithm.

Bcrypt is based on the Blowfish cipher, uses salts to encrypt passwords and is an adaptive algorithm. The algorithm incorporate an iteration count, the number of times the password is hashed, that can be increased over time. This ensures that the cost to compute the encrypted password increases even as computing power increases simply by increasing the number of iterations.

As an application developer you will not have to change any code to generate stronger encryption, simply read the number of iterations from a configuration file to generate or regenerate an encrypted password and you good to go. Of course this assume there is no flaw discovered in Blowfish at some point.

The are many libraries out there for bcrypt for your favorite language. We use the PHP and Java libraries and using it couldn't be simpler. Below is an example in Java.

import org.mindrot.jbcrypt.BCrypt;

public class UserService {

          public boolean savePassword(User user,String password){
                ...                   
                String enc = BCrypt.hashpw(password,BCrypt.gensalt(20));
                ...  
          }

          public boolean authenticate(String username,String password){
                ...
                String enc = getUserPassword(username);
                if (enc!=null){
                        return BCrypt.checkpw(password,enc));
                } else{
                        return false;
                }
          }
}

Just remember to make it hard to get to the user database in the first place.

Blogs