mirror of
https://gitlab2.federez.net/re2o/re2o
synced 2024-10-31 23:22:49 +00:00
login handler: Use constant-time comparaison for hashes.
An attacker knowing the salt but not the hash could try timming-attacks to guess a password hash and then try to find it from the hash. Although not a high risk, there is no good reason not to use a constant-time comparison, hence this commit.
This commit is contained in:
parent
3244a46d94
commit
ca08234a81
1 changed files with 7 additions and 8 deletions
|
@ -35,6 +35,7 @@ import os
|
||||||
from base64 import encodestring, decodestring, b64encode, b64decode
|
from base64 import encodestring, decodestring, b64encode, b64decode
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from django.contrib.auth import hashers
|
from django.contrib.auth import hashers
|
||||||
|
from hmac import compare_digest as constant_time_compare
|
||||||
|
|
||||||
|
|
||||||
ALGO_NAME = "{SSHA}"
|
ALGO_NAME = "{SSHA}"
|
||||||
|
@ -63,12 +64,7 @@ def checkPassword(challenge_password, password):
|
||||||
salt = challenge_bytes[DIGEST_LEN:]
|
salt = challenge_bytes[DIGEST_LEN:]
|
||||||
hr = hashlib.sha1(password.encode())
|
hr = hashlib.sha1(password.encode())
|
||||||
hr.update(salt)
|
hr.update(salt)
|
||||||
valid_password = True
|
return constant_time_compare(digest, hr.digest())
|
||||||
# La comparaison est volontairement en temps constant
|
|
||||||
# (pour éviter les timing-attacks)
|
|
||||||
for i, j in zip(digest, hr.digest()):
|
|
||||||
valid_password &= i == j
|
|
||||||
return valid_password
|
|
||||||
|
|
||||||
|
|
||||||
def hash_password_salt(hashed_password):
|
def hash_password_salt(hashed_password):
|
||||||
|
@ -118,7 +114,8 @@ class CryptPasswordHasher(hashers.BasePasswordHasher):
|
||||||
"""
|
"""
|
||||||
assert encoded.startswith(self.algorithm)
|
assert encoded.startswith(self.algorithm)
|
||||||
salt = hash_password_salt(challenge_password)
|
salt = hash_password_salt(challenge_password)
|
||||||
return crypt.crypt(password.encode(), salt) == challenge.encode()
|
return constant_time_compare(crypt.crypt(password.encode(), salt),
|
||||||
|
challenge.encode())
|
||||||
|
|
||||||
def safe_summary(self, encoded):
|
def safe_summary(self, encoded):
|
||||||
"""
|
"""
|
||||||
|
@ -159,7 +156,9 @@ class MD5PasswordHasher(hashers.BasePasswordHasher):
|
||||||
"""
|
"""
|
||||||
assert encoded.startswith(self.algorithm)
|
assert encoded.startswith(self.algorithm)
|
||||||
salt = hash_password_salt(encoded)
|
salt = hash_password_salt(encoded)
|
||||||
return b64encode(hashlib.md5(password.encode() + salt).digest() + salt) == encoded.encode()
|
return constant_time_compare(
|
||||||
|
b64encode(hashlib.md5(password.encode() + salt).digest() + salt),
|
||||||
|
encoded.encode())
|
||||||
|
|
||||||
def safe_summary(self, encoded):
|
def safe_summary(self, encoded):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in a new issue