An IS7
end user - i.e. customer, administrator, back office user, etc. - uses at least a login name and a password for authentication in the system. When the user provides a password, the system checks it against something that is stored in the database. A very straightforward approach would be to store the password in plain text and just to compare it with the user-provided plain text password. But that would be terribly insecure because the plain text passwords might be accidentally hijacked due to a software security bug or even by a corrupt employee. A password is really sensitive information since it may reveal personal data and it may empower an adversary to perform various illegal actions within the compromised system. Users often reuse their passwords and thus a stolen one may be a reason for even greater damage. However, the IS7
system does not need to remember the passwords in plain text.
In the past, MD5
, SHA-1
, SHA-2
hashes were widely used to store password hashes instead of plain text passwords. Old versions of Enfinity also did that. They stored an MD5 sum of the concatenation of the user name and the password, like this:
<Stored Password Hash> = MD5(<user_login><space><user_password>)
However, this is no longer considered to be secure though a large number of software products still use this approach.
PKCS #5: Password-Based Cryptography Standard
PBKDF2 description in RFC2898
Java ™ Cryptography Architecture, Standard Algorithm Name Documentation
MD5
and the Current Login MechanismIf user password hashes are stolen, an adversary may launch password-cracking attacks. This might be done by using rainbow tables or other dictionary attacks. A dictionary is something like a gigantic map. In its raw form it contains thousands of "dictionary words" together with their hash sums, e.g.:
MD5 | Word |
---|---|
5f4dcc3b5aa765d61d8327deb882cf99 | password |
4c2a904bafba06591225113ad17b5cec | John Doe |
... | ... |
63a9f0ea7bb98050796b649e85481845 | root |
If an attacker steals a password hash, they simply perform searches in this dictionary. Rainbow attacks are more sophisticated dictionary attacks. They are particularly dangerous since they provide a good time-memory tradeoff. Dictionary attacks are prevented by a simple technique - the usage of a salt. Salts are few random bytes (not secret) that are hashed together with the password. Salts make pre-built dictionaries useless.
However, the real problem is another one.: MD5
, SHA-256
, etc are very fast algorithms. They are designed to be fast in both software and hardware implementations. E.g. there is relatively cheaply available hardware that may calculate more than 700,000,000 MD5 hashes per second. This means that most common passwords will be easily cracked within seconds or hours. Since salts are usually known, they are not the right solution to these brute-force attacks.
Sometimes in real projects users from other systems need to be imported into an IS7
system. These users may come in various formats and they may come with some sort of password hashing, e.g. MD5
or SHA-256
. This makes the import of these users and their subsequent login into the system practically impossible without serious modifications within the login mechanism.
For some reason there might be users with different password storage mechanisms within the same system (e.g. the users were freshly imported into the system from an external source). Also, for some reason the password format may need to be changed but this cannot really happen without plain-text knowledge of the passwords. This information is available only during the login process and in a few exotic cases. The rehash support kicks in when the user sends their password to the system in plain text. If the system decides that the current storage format of the password is not appropriate, it simply calculates a new hash and saves it. This does not mean that the password has been changed. It only means that the same password is stored in a different way.
SHA-2
Variants Is More Secure Than Using MD5
Claim: Due to the insecurities inherent with MD5
, the hashing algorithm should be one of the SHA-2
variants ( SHA-224
, SHA-256
, SHA-384
, SHA-512
).
Counter-argument: These insecurities are generally not relevant to the password storage. A cryptographic hash function must at least have the following properties:
The only property relevant to password storage is the preimage resistance. This means that given a hash sum h
it is very difficult to find a message m
such that h=hash(m)
. Here h
might be the stolen hash, m
- the plain text password, and hash
- the MD5
hash function. Up to this moment there are no known practical preimage attacks against MD5
. There are attacks against its collision resistance. Thus, MD5
(or even MD4
!) is practically as safe as any SHA-2
variant for password storage.
Claim: Enfinity did not use salts, so the passwords were vulnerable to dictionary attacks.
Counter-argument: Enfinity used salts. The login name was used as a salt.
SHA-2
Family and a Salt Is a Fine SolutionClaim: Using any of the SHA-2
functions plus a salt is a fine solution.
Counter-argument: It is not. SHA-2
are very fast general purpose algorithms and salts do not prevent cheap brute-force attacks.
Claim: Forcing the users to think of very complex passwords increases security.
Counter-argument: When people are forced to remember really complicated character sequences, they usually write them on paper, put them in text files or print and hang them on the wall. This has a totally negative impact on security.
The answer to all these problems are hashing algorithms that are designed to be slow (defense against brute force) and use salt (defense against dictionary attacks). The slowness of the algorithms has no practical impact on the "honest" side since it calculates very small amounts of hashes. But it makes brute forcing harder with order of magnitude. The two most popular choices are bcrypt
(or its modern successor scrypt
) and PBKDF2
which is described in PKCS#5
. The next table tries to motivate the choice of PBKDF2
for IS7
.
Algorithm | Pros | Cons |
---|---|---|
| They are much more difficult and expensive to implement in hardware. | Not standardized. No standard built in Java support, 3rd party libraries or your own implementation are necessary. |
| Standardized, approved by NIST. Built in Java support. | It can be more easily implemented in hardware. |
Most likely, both algorithms provide sufficient security for the end users and for the selling organizations. Intershop chooses to stick to the standard ( PBKDF2
) and to provide an easy extension mechanism if someone is not fine with that.
PBKDF2
PBKDF2
is actually a key derivation function. Its usage for password hashing is not directly mentioned in the NIST documents but it is widely used as a one-way hash.
Example: The Stack Exchange Network uses the PBKDF2 for password hashing.
PBKDF2
is the IS7
choice for default hashing algorithm. This section describes it as used in the implementation.
The stored hash is calculated as follows:
<user_password_hash>=<S>PBKDF2(P, S, c, dkLen)
user_password_hash
- the password hash as stored P
- the user password in plain text S
- salt - random 64 bits long salt c
- iteration count - 2000 dkLen
- the length of the output - 256 bits
Please note that since the salt is a random 64 bit value, any password may have up to 2^64 valid and distinct hashes. Internally, PBKFD2
uses functions that are applied over and over again on the previously generated hashes. IS7
uses SHA-1
with HMAC
for this purpose, applied 2000 times. The total storage requirements per password are:
salt = 64 bits
hash = 256 bits
---------------
total = 320 bit = 40 bytes
Since these bytes are stored hex-encoded, the total space is 80 bytes per password.
IS7
The newly-built hashing API allows:
PBKDF2
with a fallback to the legacy MD5
;By default IS7
uses PBKDF2
and then falls back to MD5
. No rehashing is activated. Implementors of new hashing algorithms may follow the provided practical cookbook. Plugging a new hashing algorithm should be a trivial task.