PBKDF2


Djangoではユーザーのパスワードをハッシュでdbに保存します。

django1.3では単純にsalt+sha1でした。

    def set_password(self, raw_password):
        if raw_password is None:
            self.set_unusable_password()
        else:
            import random
            algo = 'sha1'
            salt = get_hexdigest(algo, str(random.random()), str(random.random()))[:5]
            hsh = get_hexdigest(algo, salt, raw_password)
            self.password = '%s$%s$%s' % (algo, salt, hsh)


1.4以降ではハッシュにするストラテジとして、デフォルトでPBKDF2PasswordHasherが使われるようになってます。

以下のコードでget_hasherがPBKDF2PasswordHasherを返す

    def set_password(self, raw_password):
        self.password = make_password(raw_password)

def make_password(password, salt=None, hasher='default'):
    """
    Turn a plain-text password into a hash for database storage

    Same as encode() but generates a new random salt.  If
    password is None or blank then UNUSABLE_PASSWORD will be
    returned which disallows logins.
    """
    if not password:
        return UNUSABLE_PASSWORD

    hasher = get_hasher(hasher)

    if not salt:
        salt = hasher.salt()

    return hasher.encode(password, salt)


PBKDF2が何を意味するのか、調べてみました。

PBKDF2

名称はPassword-Based Key Derivation Function 2の略でRFC2898の5.2で定義されてます。
RFC 2898 - PKCS #5: Password-Based Cryptography Specification Version 2.0


おおざっぱにいうとパスワードとsaltにハッシュ関数を繰り返しかけることによって時間がかかるようにして、ブルートフォースアタックに抵抗する、というもののようです。

ログイン試行に1秒程度かかったとしても、一般ユーザーにとっては大して影響はありませんが、ブルートフォースアタックを現実的な時間で成功させることは難しくなります。

djangoのPBKDF2PasswordHasherではデフォルトでハッシュ関数を10000回繰り返しかけます。


先日PBKDF2PasswordHasherを変更したらテストがだいぶ速くなるってのを経験したんですが、set_passwordやclient.loginのたびに10000回ハッシュ関数を実行してるんだから、時間がかかるのも納得です。


参考 : PBKDF2 - Wikipedia, the free encyclopedia