Issue 2551171
Created on 2021-11-24 22:36 by rouilj, last changed 2022-05-12 02:51 by rouilj.
| Messages | |||
|---|---|---|---|
| msg7371 | Author: [hidden] (rouilj) | Date: 2021-11-24 22:36 | |
Somebody asked if Roundup supported Have I been Powned (https://haveibeenpwned.com/) using the password API: https://haveibeenpwned.com/API/v3 It doesn't but along the lines of https://wiki.roundup-tracker.org/TestPasswordComplexity a similar mechanism can use: https://pypi.org/project/pyhibp/ to get a password check. Also adding support for specifying an API key (https://haveibeenpwned.com/API/Key) in: detectors/config.ini for the tracker allows use of checks for the email address(es) of the user that can be done in a detector. |
|||
| msg7425 | Author: [hidden] (rouilj) | Date: 2021-12-21 01:06 | |
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
|
|||
| msg7515 | Author: [hidden] (rouilj) | Date: 2022-05-12 02:51 | |
Since this is documented on the wiki, I consider it done. |
|||
| History | |||
|---|---|---|---|
| Date | User | Action | Args |
| 2022-05-12 02:51:25 | rouilj | set | priority: normal assignee: rouilj messages: + msg7515 status: new -> closed resolution: fixed |
| 2021-12-21 01:06:58 | rouilj | set | messages: + msg7425 |
| 2021-11-24 22:36:58 | rouilj | create | |