Chico Digital Engineering
 

  • Source Forge Project
  • Download Now
  • Web Tool


  •  

    Perl/Javascript MD5 Secure User Authentication

    This project implements an MD5-based encryption scheme on both client and server machines to allow encrypted password protection for web-based Perl/CGI applications. Although there are many free Perl/CGI application for password protection, only a few use MD5 on the server-side, but the password still travels over the internet as plain text. All server-side only schemes (like .htaccess password protection) are completely open to packet-sniffing. With this scheme, the browser JavaScript encrypts the password on the client's machine, and session tracking allows only one response per session ID, making simple packet-sniffing and session replaying much more difficult.

    Paul Johnson wrote the JavaScript MD5 code, and released it under the Open Source BSD license. Without this contribution, and the guidance of his web site this project would not be possible.

    This is a one-way encryption scheme: the password is never transmitted or stored as clear text on the client or server, and thus cannot be recovered. It uses cookies to maintain the user session.

    Session authentication verifies that the login page was created by the server and the user response is within 30 seconds of the login page request. The login response hash is the MD5-encrypted user name/password hash combined with the unique session ID, ie, it's unique and it can't simply be re-presented to the server for authorization. The latest release supports file-level locking of the session database; this ensures that only one valid session response is possible. Thanks to Ashish Desai for help on this.

    Here is a full description of the MD5 algorithm.

    How This Application Works

    Hash-based authentication methods work via a challenge-response mechanism. The server sends a random challenge. The client combines the random challenge with the password, and computes a one-way hash. The client sends the hash to the server, which performs the same computation. If the client's supplied hash matches the servers computed hash, the authentication succeeds.

    1) The adminstrator adds a user name and password to the user database on the
    server via the shell utility addUser.pl. The name/password are saved as an 
    MD5 encrypted hash. The theory behind MD5 is that it would be very difficult to
    determine the originating strings for any given hash. The hash is a unique
    signature, but doesn't reveal the original password.
    
    2) The remote user accesses the main program via their browser. 
    
    3) During this initial request, the server looks at the browser cookies; if the
    user has already been authenticated, they will have cookies set (with a duration
    of 24 hours by default). If a cookie exists for the application, then it's value 
    will be tested against the hashed name/password and IP address for that users
    current session. If this test passes, the user is allowed access without further 
    intervention. Otherwise, the client will be shown the login screen. Cookies will 
    index the IP address of the client. During the initial user authorization, their 
    IP address is stored, referenced to their cookie ID. The session cookie and the 
    current environment IP address must match during future accesses, or the cookie 
    session validation will fail. 
    
    4) The server-side request for the login screen will create a new session ID value
    and add it to the session database, also storing the time of the request.
    
    5) When the remote user submits a name/password, the client-side javascript then:
        a) MD5 encrypts their user name and password. 
        b) MD5 encrypts the user/password hash with with the session ID value.
        c) Returns the session ID and the encrypted user/password/sessionID hash 
           to the server.
           
    6) The server authenticates the user if: 
        a) The session ID returned is a valid open session and
        b) The session ID was requested less than 30 seconds ago and
        c) The user/password hash stored on the server, hashed with the sessionID,
           matches the response from the remote client. Note that the response hash
           is unique because it combines the user/password hash (which is constant) 
           and the sessionID string (which is always different). Only one response
           is allowed for each sessionID, so replaying the response hash to gain 
           authentication doesn't work. 
           
    7) If the authentication fails a failure message is returned to the remote client
    browser.
    
    8) If the authentication is successful, the HTTP header will pass a cookie to the
    remote client browser, allowing them access for 24 hours (by default). Note that
    because of this, the set cookie string could be theoretically stolen by packet 
    sniffing and used as a bypass to the authentication process, although there is
    now the additional hurdle of determining the IP address of the client. A user 
    can have a different IP address for different sessions, but once authorized at 
    a certain IP address, the validity of that session cookie is tied to that address. 
    
    

    I'm not a security expert by any means, and so I'm not qualified to say exactly how safe/unsafe this scheme is. Judge for yourself, I'd be curious to hear what you think.

    Note that this module does NOT provide security agains eavesdropping or hijacking. A positive identification can be followed by an attacker stealing the connection. This scheme is also open to a man-in-the-middle type attack. Also, the cookie itself could be sniffed, which allows an authentication bypass. So my summary is that this is not SSL strength solution, but it's better than using .htaccess or other methods that transmit the name/password information as plain text.

    I don't have time to work on this code right now, so hack away if you have any other ideas to improve it. Another thing that would be cool: an email-based admin approval scheme for new users.

    This application was intended to be an easy drop-in password protection scheme for Perl/CGI applications. It could easily be updated to use other encryption methods (if both are available as Perl and Javascript). In it's current form, it is a working code framework, but it doesn't have all the nice features of a some password login applications (new user signup, admin screens, etc).

    Install Notes This can be difficult to install because of file permission issues. Often it doesn't work because the .db files can't be read AND written by the web server process. The debug messages aren't clear, and there isn't much documentation for debugging. If you don't know Perl and unix filesystems well, you might get stuck...

    August 25th, 2003: Version 0.31: 1) Change license to LGPL (previously was GPL), so code can be used by commericial products. 2) Bug in javascript submit fixed. Thanks to Stefan Höfs for pointing this out. 3) additional code comments.

    August 27th, 2002:Version 0.30: Fixed a bug in the session db cleaning. Now used as the default mechanism to clean all invalid sessions. Moved separate javascript code for MD5 encryption into the perl script, to make the installation easier. since the MD5 algorithm is public, it doesn't matter that the user can see it, right? Cookies now are keyed to the IP address: a user can have a different IP address for each session, but once authorized at a certain IP address, the validity of that session cookie is tied to that address. This is just another hurdle which I know can be overcome, since a hacker can just transmit the right IP address; but at least now they would have to know what that IP address is... I think... : )

    August 2nd, 2002:Version 0.21: Lock code was integrated into the LoginMD5.pm module to make installation easier.

    July 31st, 2002:Version 0.20 Changes: I figured out that the sessionID can be forced to be unique; now only one response is possible for each session ID, and by locking the database file (with unix flock()) this ensures only one correct authentication response is possible per sessionID. The session ID is now randomly generated (with a new algorithm using Perl rand()). For stronger randomization of the session ID, the Perl CPAN module Math::Random::MT can be enabled in LoginMD5.pm (at line 170). Other changes: there are now both a 'addUser.pl' and 'removeUser.pl' command line utilities.

    July 12th, 2002:Now uses a cookie to maintain the user session as valid (for 1 day, by default).

    July 6th, 2002: I just released a working prototype that can be downloaded from SourceForge. Any feedback/bug reports would be appreciated.

    Alan Raetz alanraetz@chicodigital.com

    SourceForge Logo