I consider the possibility of improving password security by increasing the hashing iteration count for short passwords.
The security benefits I see of this practice are:
- Short passwords are better protected by making brute force more expensive.
- Users are incentivized to use longer passwords.
Is this a good security practice?
Is this an already established practice with an official name?
The system I'd like to use this in already has a plugin architecture for password hashers, it does not have any centralized way to enforce a password policy and I might not have the mandate to enforce a password policy.
I have considered possible drawbacks of this approach and for each potential drawback I could think of I found reasons why it isn't a problem.
Potential leak of password length: Since the password database only stores the minimum iteration count used for longer passwords and the effective iteration count is calculated on the fly, the database cannot leak any information about password length. Timing attacks aimed at deducing the password length will not work either. An attacker attempting to brute force passwords will see the time it takes to validate a password vary depending on the length of the password the attacker attempts not the user's actual password. That means there is no way an attacker performing such an attack would learn the length of the user's password.
Potential DoS attacks: The increase in CPU consumption to validate passwords could be a DoS attack vector. But this attack vector already exists even when the iteration count is a fixed number high enough to match common recommendations. And the way to defend against this kind of DoS attack is to rate limit password attempts per client IP range. This defense against that class of DoS attacks will still work assuming one apply a minor tweak to adjust the permitted rate according to CPU consumption.
User experience: The slowdown in login could be argued to be bad user experience. I'd rather phrase it as incentivizing users to use longer passwords and call it a feature. At login time I could let users know that they can get faster logins by using a longer password. In particular if this could be a widespread practice it may give users the expectancy that longer passwords are faster, which would be a win to everybody.
From my considerations this far I have only found advantages to this idea. But I understand that there may be drawbacks which I may have missed. Are there reasons why one should not make iteration count higher for short passwords?
In order to avoid any ambiguity of what the idea I have in mind is, I have written an implementation of this idea in the Django framework. The only functional difference between the builtin PBKDF2PasswordHasher
and my modification is these two lines:
if len(password) < recommended_length:
iterations *= progression_factor**(recommended_length-len(password))
The full implementation looks like this:
import base64
import hashlib
from django.contrib.auth.hashers import PBKDF2PasswordHasher
from django.utils.crypto import pbkdf2
def progressive_pbkdf2(password, salt, iterations, digest,
recommended_length, progression_factor):
if len(password) < recommended_length:
iterations *= progression_factor**(recommended_length-len(password))
return pbkdf2(password, salt, iterations, digest=digest)
class ProgressivePBKDF2PasswordHasher(PBKDF2PasswordHasher):
algorithm = "progressive_10_2_pbkdf2_sha256"
def encode(self, password, salt, iterations=None):
assert password is not None
assert salt and '$' not in salt
if not iterations:
iterations = self.iterations
hash = progressive_pbkdf2(
password, salt, iterations, digest=self.digest,
recommended_length=10, progression_factor=2)
hash = base64.b64encode(hash).decode('ascii').strip()
return "%s$%d$%s$%s" % (self.algorithm, iterations, salt, hash)