[OPEN-ILS-DEV] Self-serve password reset thoughts
Dan Scott
dan at coffeecode.net
Mon Mar 29 00:35:09 EDT 2010
On Sun, 2010-03-28 at 21:47 -0400, Bill Ott wrote:
> Ours is not quite as complex, but has been serving us well since we put
> it into production 18 months ago.
>
> We simply accept a barcode and email address. If they match a given
> account, the password is reset to a random 5-digit integer, which is
> emailed to the address. The email of course does not contain a barcode
> or username, nor a link or any indication of where the password is to be
> used, so the receiving party would need to already have that information
> for it to be of use. Because the value does not meet our complexity
> requirements, it must then be reset by the user following the first login.
>
> The most common complaint comes from individuals that do not have a
> current email address in their account, and therefore cannot get the
> form to reset their password.
>
All bets are off when you're sending anything via email, I suppose.
My concern about your approach is that attacks become pretty straight
forward: you just need to know a user's user name (or barcode) + email
address to reset their password to a 5-digit integer. In our context,
these two pieces of information would be pretty easy to come by
(consider two people that might have had a relationship go sour). Also,
given the institutional nature of our Evergreen install, our users' user
names tend to be their institutional email addresses, or the prefix part
of their email address, so this combination is often predictable.
To illustrate why I'm implementing something along the lines of what I
linked to, consider what could happen if someone malicious does have the
user name or barcode + email address in hand.
In the best case scenario, nothing happens and we're all happy. In
reality, this is probably the vast majority of the cases that would
occur.
In a slightly worse scenario, however, a malicious user armed with this
knowledge just annoys the heck out of the targeted user, as the victim's
password could be reset continuously by simple manual requests on the
part of the malicious user.
In a slightly worse scenario, the malicious user would script the
password reset request to occur every five minutes, effectively locking
the victim out of their account. Even though the victim could request
their own password reset, the malicious request will follow within the
next five minutes, locking them out again.
In a worse scenario, the malicious user combines the password reset with
a brute force attack; now that the password strength has been reduced to
a mere 99,999 combinations, the malicious user stands a pretty good
chance of issuing the password reset request at some time when the
victim is not paying attention to email (say, at 1:00 AM). If they then
fire off one login attempt per half-second, they will have tested 50,000
passwords in 6 hours. If they hit the right password, then they can
change the victim's email address and password; as the email address has
been changed, it prevents the victim from resetting their password
without a visit or call to the circ desk (depending on library policy).
Or more dire, if the malicious user access manages to log in, they can
view the victim's contact information - which could have severe
consequences if, say, the victim had moved to avoid the malicious user -
then issue another password reset request. The victim just sees
back-to-back "Your password has been reset" email messages and otherwise
does not know what has happened.
So, even though the cases where things go this sour are likely going to
be few and far between, and once they get this sour it really needs to
get into the hands of the authorities, I still think it's worthwhile to
take some care in implementing this to try and avert these avenues of
attack. About four hours in, I have the
open-ils.actor.patron.reset_password.request() call generating entries
in the actor.usr_password_reset table if given a valid barcode or user
name, subject to a maximum number of concurrent active requests per user
(based on OU settings for max concurrent sessions and request
time-to-live).
Still need to:
* cache the "throttle mode" setting so that we don't have to hit the
database for every request if someone is attempting a denial of service
via this route
* send email with the proper URL to visit - hello, template toolkit
* implement the Web interface listening to the special UUID URLs that
generate a simple password reset form with validation based on the
home_ou or ancestor regexes if a valid UUID is hit; probably want to
cache these, too, for a minute or so
Give me another four hours of clear-headed time to focus and I think I
should have a reasonable implementation together - subject to anyone
poking significant holes in my current plans for a secure approach, of
course.
More information about the Open-ils-dev
mailing list