Yesterday, my brother and I had a discussion on encrypting/hashing passwords. He passed along an article that talked of rainbow tables and hashing. This sparked me to do some searching of my own code as well as some on the net...and I discovered the following...
The article talks of using strong hashing and something called a nonce. Using this nonce, you can better insure that the information being passed back is from a user and not an attack or hack. Think of one of those fobs you get that have a 4 digit code display for authenticating. Pay-pal issued one a year or 2 back.
The article talks of using this nonce as a salt. Using salts for hashes isn't anything new, but sometimes we need to look a bit more carefully at our salts...for example...lets say upon hashing the password before I compare/store it in the database, I hash it with username or another non-random constant. It is feasible to create a rainbow table hashed with this constant, thus a security flaw. The nonce has to be random or derived from some group of elements as to not be easily discovered. Maybe for apex land a combination of session state, date, app ID, etc?
Another suggestion by the author is to make the compare password function longer in time. A hacker will pass on a system that takes say 4 seconds for each password lookup rather than sub second lookups. Scott and I thought maybe in our code a counter that will trigger a DBMS Sleep with (count * 2) for each password try. So 1st try, takes 2 seconds, second, 4, third, 6, and on and on...
The author also suggests not using MD5. The DBMS_CRYPTO package does have some other stronger alternatives.(SHA1)
Lets take a closer look at some code...consider the following:
l_hashed_raw := DBMS_CRYPTO.HASH (l_user_password, DBMS_CRYPTO.hash_MD5);
It is feasible that with a rainbow table hashed with MD5 and access to this row, I could find matches of weak passwords. We need a nonce. Adding a 16 or 32 bit string of random values makes the rainbow table just too damn big, consisting of quadrillions of rows. That's alot of rows. We can store that string along with the hash to use when logging in again if we wish. So modify the code to something similar to this:
Even if the hashed password is retrieved from the database, an attacker would have to create a rainbow table with the correct salt for all of the know words in a dictionary for a dictionary attack. Quoting from wikipedia:
Assume a user’s (encrypted) secret key is stolen and he is known to use one of 200,000 English words as his password. The system uses a 32-bit salt. The salted key is now the original password appended to this random 32-bit salt. Because of this salt, the attacker’s pre-calculated hashes are of no value. He must calculate the hash of each word with each of 232 (4,294,967,296) possible salts appended until a match is found. The total number of possible inputs can be obtained by multiplying the number of words in the dictionary with the number of possible salts:
To complete a brute-force attack, the attacker must now compute about 800 trillion hashes, instead of only 200,000. Even though the password itself is known to be simple, the secret salt makes breaking the password increasingly difficult.
A nonce can also be used to secure transactions...use the nonce as an apex app item to pass into a procedure to check for authenticity. So for a delete procedure, one of the vars to be taken in is a nonce. The procedure looks at this nonce, verifies it, and proceeds if the nonce checks out, like a checksum. This can also be applied to our password check procedure for double security. Check out this page here, not apex but the concepts are similar.
To sum this up, we need to take a good look at how we are hashing and storing our passwords. Rainbow tables do exist and can be used to attack our sites we build (apex or not), but with a little planning and clever thinking, we can prevent this.