Skip to content

Commit

Permalink
Use constant time string comparisons
Browse files Browse the repository at this point in the history
This uses constant time string comparisons everywhere that looked plausibly like it
might matter:

 - Plaintext password comparison
 - Digest nonce comparison
 - Digest hash comparison

Fixes #82
  • Loading branch information
brendanlong committed Apr 29, 2019
1 parent 3f743c6 commit 788d42e
Showing 1 changed file with 29 additions and 4 deletions.
33 changes: 29 additions & 4 deletions flask_httpauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@
__version__ = '3.2.4'


try:
from hmac import compare_digest
except ImportError:
import operator

# This fallback is not constant-time, but making it constant-time
# introduces additional complexity. For full-secure password
# comparison, applications should use Python 2 >= 2.7.7 or
# Python 3 >= 3.4, or use hashed passwords.
compare_digest = operator.eq


class HTTPAuth(object):
def __init__(self, scheme=None, realm=None):
self.scheme = scheme
Expand Down Expand Up @@ -142,8 +154,18 @@ def authenticate(self, auth, stored_password):
except TypeError:
client_password = self.hash_password_callback(username,
client_password)
return client_password is not None and \
client_password == stored_password
if stored_password is None or client_password is None:
return False

try:
stored_password = stored_password.encode("utf-8")
except AttributeError:
pass
try:
client_password = client_password.encode("utf-8")
except AttributeError:
pass
return compare_digest(client_password, stored_password)


class HTTPDigestAuth(HTTPAuth):
Expand All @@ -169,7 +191,10 @@ def default_generate_nonce():
return session["auth_nonce"]

def default_verify_nonce(nonce):
return nonce == session.get("auth_nonce")
session_nonce = session.get("auth_nonce")
if nonce is None or session_nonce is None:
return False
return compare_digest(nonce, session_nonce)

def default_generate_opaque():
session["auth_opaque"] = _generate_random()
Expand Down Expand Up @@ -235,7 +260,7 @@ def authenticate(self, auth, stored_password_or_ha1):
ha2 = md5(a2.encode('utf-8')).hexdigest()
a3 = ha1 + ":" + auth.nonce + ":" + ha2
response = md5(a3.encode('utf-8')).hexdigest()
return response == auth.response
return compare_digest(response, auth.response)


class HTTPTokenAuth(HTTPAuth):
Expand Down

0 comments on commit 788d42e

Please sign in to comment.