Roundup Tracker - Issues

Message7425

Author rouilj
Recipients rouilj
Date 2021-12-21.01:06:58
Message-id <1640048818.76.0.292007873029.issue2551171@roundup.psfhosted.org>
In-reply-to
Adding this function allows checking the entered password for
exposure on have I been powned.

import hashlib
import requests
from roundup.exceptions import Reject

def check_pw_hibp(password, mode="change"):
   # encode to unicode string and return a hex encoded sha1 hash
   pwhash = hashlib.sha1(password.encode()).hexdigest()
   # search hibp using the first 5 hash characters
   try:
       rqst = requests.get('https://api.pwnedpasswords.com/range/' + pwhash[:5],
                        timeout=2.5) # timeout 2.5 seconds
   except requests.exceptions.Timeout:
       return False # don't let API failure stop login or change
   # turn string like FA31ED547EE63D61B812DABE2F37D2AAFE2:2\r\n<another hash>
   # into list element of FA31ED547EE63D61B812DABE2F37D2AAFE2
   res_hash_list = [ x.split(':')[0] for x in rqst.text.split('\r\n') ]
   # hibp returns hash residual after removing first 5 requested chars
   # so search for it.
   if pwhash.upper()[5:] in res_hash_list:
      if mode == 'change':
         # reject change of password to the password value
         raise Reject("Password has been exposed on have i been powned. ")
      elif mode == "login":
         # Evaluates to true - have been found on hibp. Allow
         # the user to login (and change password) but provide an error message.
         return "Warning password has been exposed on have i been powned. Change password"
   return False # false == not found in hibp

Using the technique in:

  https://wiki.roundup-tracker.org/TestPasswordComplexity

and calling this with mode="change" allows you to check it when it gets changed.

You can put this in the login flow using the technique in:

  https://wiki.roundup-tracker.org/LoginWithEmail

so the password is checked for exposure on every login. Use code like:

  r = check_pw_hibp(self.form['__login_password'].value)
  if r:
     self.client.add_error_message(r)
     
in the login action wrapper.

Probably checking in both places is a good idea. One makes sure the user
isn't starting off with an exposed password and the other verifies that it
is still unexposed.

I put this on the wiki as well.
https://wiki.roundup-tracker.org/CheckForExposedPasswordHIBP
History
Date User Action Args
2021-12-21 01:06:58rouiljsetmessageid: <1640048818.76.0.292007873029.issue2551171@roundup.psfhosted.org>
2021-12-21 01:06:58rouiljsetrecipients: + rouilj
2021-12-21 01:06:58rouiljlinkissue2551171 messages
2021-12-21 01:06:58rouiljcreate