| ||
Based on everything I said earlier, I'd like to give an example of a well-designed (in my opinion) authentication and authorization system.
I should mention that this is just an example, and a real situation can require strengthening the protection or, conversely, removing certain limitations.
Before writing code, I have to decide, on which methods authorization and authentication should be based and which features should be implemented.
Naturally, the system should fulfill all necessary tasks . The example I'm going to present is just an example, and it can't meet all the requirements of a real-life system.
The ideas behind this authentication and authorization system are the following:
Primary authentication is done using a login and a password. The login and the password are case-sensitive.
Authorization is based on the access level ID returned by the authentication system. The ID value can be as follows : 0 indicates guest access or no access, 1 means user access, and 2 provides administrator access.
Information about the users is stored in a MySQL database.
After successful primary authentication, the user gets a 128-bit unique session ID.
The session ID is stored among the client's COOKIE values.
The lifetime of the COOKIE values that contain the session ID is one session.
On the server party, the lifetime of the session ID is 30 minutes.
After authorized access to a document or a service, the lifetime of the session ID is updated.
Users' passwords aren't stored unencrypted on the server. Rather, 128-bit password hashes are stored. The md5 hash function is used.
The following user information is stored in the database: the login, the password hash, the access level, the session ID, the session ID lifetime, and the user's e-mail address.
A password recovery subsystem is implemented. After a demand containing a user's login, a newly-generated password is sent to the user.
In an actual system, it would be best to replace the last item with the following:
A password recovery subsystem is implemented. After a demand containing a user's login, a link with a random ID is sent to the user. After the user follows this link with his or her browser, a newly-generated password is displayed in the browser window.
The replacement of the last item is aimed at preventing an attacker from changing a user's password. Otherwise, the attacker can change the password. If the user lost access to the e-mail account or made a mistake when entering the e-mail-address, he or she won't be able to control the system account any longer.
For the system to work, I should create a database table. Let it be as follows:
-bash-2.05b$ mysql -u root Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1 to server version: 4.0.18 Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> use book1 Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> describe reguser; +-------+--------------+------+-----+---------+----------------+ Field Type Null Key Default Extra +-------+--------------+------+-----+---------+----------------+ id int(11) PRI NULL auto increment login varchar(255) pass varchar(255) level int(11) 0 sid varchar(255) exp int(11) 0 +-------+--------------+------+-----+---------+----------------+ 6 rows in set (0.02 sec) mysql> select * from reguser +----+-------+----------------------------------+-------+-----+-----+ id login pass level sid exp +----+-------+----------------------------------+-------+-----+-----+ 1 user1 20a0db53bc188la7f739cd956b740039 1 0 2 user2 1926f73f97bf1985b2b367730cb75071 1 0 3 admin 25e4ee4e9229397b6bl7776bfceaf8e7 2 0 +----+-------+----------------------------------+-------+-----+-----+ 3 rows in set (0.00 sec)
The users' passwords are user1pass , user2pass , and adminpass , respectively.
The following is the code of the authentication module. The function returns the user's access level.
login.inc.php |
---|
<? if(!defined('Phoenix')) exit; // Protection against include // file execution mysql_connect("localhost", "root", ""); mysql_select_db("book1"); function auth() { global $_COOKIE, $_POST; $login=addslashes($_POST['login']); // Avoiding SQL injection $pass=md5($_POST['pass']); // The password hash is needed. if(!empty($login)) // Primary authentication { $q=mysql_query("select id, level from reguser where BINARY login='$login' and BINARY pass='$pass'"); if($r=mysql_fetch_object($q)) {// Authentication is successful, a session ID is returned $sid=md5(uniqid(rand(),1)); $time=time()+ 60*30; mysql_query("update reguser set sid='$sid', exp=$time where id={$r->id} "); setcookie("sid", $sid, 0, "/"); return $r->level; } } // If the primary authentication wasn't successful or wasn't performed, // the secondary authentication is done. $sid=addslashes($_COOKIE['sid']); // Avoiding SQL injection. Although // the program set the session ID in // a cookie, there is no guarantee // that nobody changed it. if(!empty($sid)) { $time=time(); $q=mysql_query("select BINARY id, level from reguser where sid='$sid' and exp>=$time"); if($r=mysql_fetch_object($q)) { return $r->level; } } // Authentication is unsuccessful. A form suggesting that the user enter // a login and a password is displayed. echo " <html><body> Authentication is required <form method=POST> name: <input type=text name=login><br>password: <input type=password name=pass><br> <input type=submit> </form> </body> </html> "; exit; // Execution is interrupted } ?> |
Authorization is done in particular documents and services depending on the access level ID, as shown in the next examples.
http://localhost/4/user.php |
---|
<? define('Phoenix', 1); include("login.inc.php"); if(auth()>=1) echo "Welcome to the user account"; else echo "You don't have necessary privileges"; ?> |
http://localhost/4/admin.php |
---|
<? define('Phoenix', 1); include("login.inc.php"); if(auth()>=2) echo "Welcome to the administrator panel"; else echo "You don't have necessary privileges"; ?> |
The password recovery module could be written in a similar manner.
This system requires that support for session cookies is enabled in the user's browser.
| ||