perlmeditation
maverick
With the recent...um...events surrounding [tye], there has been a good deal of discussion about
password management for sites such as PM. In light of that, I'm going to describe the
technique I've used (and plan to use again) in hopes of spreading
enlightenment, as well as resolving any flaws in the technique.
<readmore>
<p>
<h4>The setup</h4>
Passwords are stored encrypted via [kobe://Crypt::PasswdMD5] or some other equivalent
module. I chose this one because it seems perfectly suited to the task and because
there are javascript implementations of it (I'll explain why shortly). This is done to
prevent the passwords being exposed if the database is compromised in some form, either
by hack or by [tye] (sorry couldn't resist).
<p>
There are two ways in which the login process can be handled. Basically you have to prevent
the username/password from being transmitted in the clear across the net. Any black hat packet
sniffing could catch it.
<ol>
<li>Make the pages that handle the login process only be accessible under SSL.
This is easy and straight forward to implement and works. The downside is you
have to pay the CA (certificate authority) tax, or live with the annoying
'do you trust this site?' dialog.
<li>Don't send the password in the clear in the first place. There are several different
Javascript implementations of the PasswdMD5 algorithm, you can use this to encrypt the password
BEFORE it is send to the server.
</ol>
<p>
The encrypted password is validated against the database and if they match a
[kobe://Apache::Session] is created for this user. A cookie is passed back to
the browser that contains the session id. No other cookies will be used.
Into the Apache::Session goes the uid of the user, the IP from which they
connected, and the time stamp. Since the user has no way to access the
contents of the apache::session, you can consider this data untainted.
<p>
The reason for storing the IP of the host that they connect from is to prevent
the session from being hijacked if the cookie can be obtained via packet
sniffing. Each time that the cookie is passed back, the connected host's IP
is compared against the one in the session (which was set at the time of the
successful login), if they don't match then it's been hijacked.
<p>
The time stamp is used for an inactivity timeout...to prevent the 'I left
myself logged in while I went to lunch and somebody sat down at my computer
and sold my body on eBay' syndrome.
<p>
<h4>Issue: Changing password</h4>
Alteration of the password is done Unix style. The page that the
authenticated user accesses contains 3 fields. current password, new password
and new password (again). They enter their current password and the desired
new one twice (to make sure there are no typos), if they enter the correct
current one, and the 2 new ones are the same the password is changed. This
page follows the same security rules as the login page...it's either SSL or
the passwords are encrypted before they are sent. The reason for prompting for
the current password is to prevent the scenario where the person *JUST* got up
from there computer and someone ran in before the session expired. This also
would prevent a malicious user from changing the password if they do manage to
hijack the session somehow. Also the new password is fed through a password
strength checker (Unix has these, I'm sure there's a CPAN mod for it). What
good is a secure password scheme if luser 'john' set's his password to
'John'?
<p>
<h4>Issue: I forgot my password</h4>
Since the passwords are stored encrypted, then you can't very well send it to
them. So, the password can be reset to a new random one using
[kobe://Crypt::RandPasswd] and emailed to the email address stored in the
database for user john. If we have the public PGP key for 'john' then we PGP
encrypt the message. (it does no good to email the password in the clear if
there's a black hat sniffing traffic).
<p>
This opens the door for a DOS attack via the 'forgot my password' link,
or someone else resetting john's password for him.
<ul>
<li>The DOS part is solved by adding a 'LastForgotDate' field to john's data and only allowing his password
to be reset once a day.
<li>The malicious change part can be solved by adding
another set to the process. Once john enters his username on the forgot
password page, he's present with another screen that asks for the answer to a
personal question ie, "what is your mother's maiden name?". If the correct
answer is given then 'john's password is reset (john supplied the question
and answer as part of the registration process).
</ul>
<p>
<h4>Issue: I forgot my password AND the email address I registered with is
non-accessible</h4>
This is one I'm not sure how to handle...I've never run across this problem
and it very well may be a fringe condition that just requires calling up the
sysadmin and getting him/her to reset it (using the secret Q/A like the change
password does)
<p>
<h4>Wrap up</h4>
So, if we were storing all this info in a relational database, then the user
table would contain at least
<br>
<center>
<table>
<tr><td><b>id</b></td> <td>database generated numeric id</td></tr>
<tr><td><b>username</b></td> <td>the username</td></tr>
<tr><td><b>password</b></td> <td>PasswdMD5 encrypted password</td></tr>
<tr><td><b>email</b></td> <td>email address to send reset password to</td></tr>
<tr><td><b>lastresetdate</b></td> <td>date of last password reset (prevents DOS attack)</td></tr>
<tr><td><b>question</b></td> <td>secret question to be asked if the password needs to be reset</td></tr>
<tr><td><b>answer</b></td> <td>answer to the question (used to prevent malicious password resets)</td></tr>
<tr><td><b>pgpkey</b></td> <td>user's public PGP key (to prevent the 'here is your new password email from being sniffed)</td></tr>
</table>
</center>
<p>
The questions my fellow monks are:
How can this system be defeated?
What problems does it have?
How can it be improved?
<p>
/\/\averick<br>
</font>