Password for a page. Part II.

Password for a page. Part II.

Password for a page. Part 4. Cookies.

This method is possible to use in cases when we deal with a plenty of users and their constantly changing contingent. We also use it when we are to make convenient entry – to impossible entrance into the system by input of login and password in the form on the page.

We draw a form and make a file which gets login and password (I’ve already described protection from selection, now you are to write it yourselves).

// processing string with login 
$login = str_repalce(""", "", $login);

$login_result = mysql_query("SELECT id FROM user WHERE 
  login="$login" AND pass="". md5($pass). "'");

if (!mysql_error() && @mysql_num_rows($login_result)==1) {

/* delivery of cookies. It’s better to definite cookies’ names and path 
within unified attached file in order to evade confusion. */
   setcookie($COOKIE_LOGIN_NAME, $login, time()+3600, $COOKIE_PATH);
  setcookie($COOKIE_PASSW_NAME, $pass, time()+3600, $COOKIE_PATH);

/* Immediately after the entrance user is redirected to the closed with a password address */
  header("Location: /somepath/");
  exit;
  }
elseif (!mysql_error()) {

/* output of an error message and repeated input form */
  print ("Invalid login or password. ");
  }
else
  print (mysql_error());

All shut pages call out a file in which fidelity of a password obtained from cookie is checked:

$login = str_repalce("'", "", $HTTP_COOKIE_VARS[$COOKIE_LOGIN_NAME]);
$login_result = mysql_query("SELECT id FROM user WHERE 
  login="$login" AND pass="". md5($HTTP_COOKIE_VARS[$COOKIE_PASSW_NAME]). "'");

if (!mysql_error() && @mysql_num_rows($login_result)!=1) {

/*If there is no such a string in the table, a user is redirected to the entrance page. */
  header("Location: /login.php");
  exit;
  }
else
  print (mysql_error());

Cookies’ names will be used I some places, so you’d better place them together beforehand (for example, by declaring constants) in order to evade several corrections.

As you can see the password will run through the channel and lay together with cookies in the open uncoded form. It’s rather dangerous. At the absence of the owner you may come to the computer, look into the file where browser keeps cookies and write down password on the sheet of paper (in case everything is common in the local net, there’s no need in coming to the computer, it’s possible to filch the password at the owner’s presence).

To evade this you should code your password. As a possible variant use hash õýø md5. Here it’s impossible to see the password and enter the system having written it on the sheet of paper or through ‘copy-paste’. This way you may enter under the password and unknown to your friend into web-interfaces which build authorization on the sessions. So the last thing you can do this way is to change cookie by each download of a page.

Once I did such schedule myself: there is a column with the date of last addressing in the users’ table. This date of last addressing and password coded through md5 user gets by each addressing. The system takes cookie with login, extracts this string from the base, generates hash from last_log and passwd fields and compares it with the obtained one. If they coincide, you may let the user in. For the better safety you may add assertion for the cookie’s expiry – a cookie should expire after half an hour of non-activity and correspondingly date of the last log in the base should be less than half an hour ago.

$login = str_repalce("'", "", $HTTP_COOKIE_VARS[$COOKIE_LOGIN_NAME]);
$login_result = mysql_query("SELECT * FROM user WHERE 
  login="$login" AND last_log>DATE_SUB(NOW(), INTERVAL 30 MINUTE)");

if (!mysql_error() && @mysql_num_rows($login_result)==1) {
/* Obtain a table’s string and form the hash from necessary fields. */
  $current_user = mysql_fetch_array($login_result);
  $hash_to_check = md5($current_user["passwd"]. "Z – for nobody to guess ".
                   $current_user[log_time]);
  
  if ($hash_to_check == $HTTP_COOKIE_VARS[$COOKIE_HASH_NAME]) {
    $current_time = time();
/* Renewal of the last entrance field and delivery of a new cookie. */
    mysql_query("UPDATE user SET last_log="". date("Y-m-d H:i:s", $current_time). "" 
      WHERE login="$login"");
    setcookie($COOKIE_HASH_NAME, md5(date("Y-m-d H:i:s", $current_time). 
       "Z – for nobody to guess ". 
        $current_user["passwd"]), $current_time + 1800, $COOKIE_PATH);
    }
  else {

/* In case of non-coincidence of the hash a user is redirected to the system entrance page. */
    header ("Location: /login.php");
    exit;
    };
  }
elseif (!mysql_error() && @mysql_num_rows($log_result)!=1) {
  header("Location: /login.php");
  exit;
  }
else
  print (mysql_error());

Of course, it’s better to pick out "Z – for nobody to guess " into the single variable; and it’s also better to use ip-address of a guest instead of this string (or, for terminating dial-up the first two or three numbers of the ip-address).

By the way, about IP-address. You’d better check it but not the whole address: check only first two (for IPs beginning with number which is less than 127) or three (more than 127 correspondingly) numbers of the address. This will save user of bad and terminating dial-up the necessity to authorize again after the connection break and at the same time will make entrance impossible for the hacker who has filched the cookie. Of course, he won’t be able to ring up or enter through another provider – there’s another pull’s address. But these are not our problems. In the same way we shouldn’t deal with the passwords’ filching within a firm.

At this place all the ‘tricks’ came to the end. We cannot do more reliable defense. Nobody will go into file and fetch hash and select it. It will be easier to place a sniffer between user and interface and find a password using it. You may place a trojan which will memorize everything that user has written on the keyboard but we are not to deal with these problems. To get protection from the channel’s run-through you are to use connection of SSL type or data ciphering.

Password for a page. Part 5. Sessions.

Why did I write an article about cookies? I did it in order to prevent readers from having a flat picture before their eyes. Not everyone has already got the fourth php version and they are not supported in the third one. Even more than that – sessions aren’t obligatory everywhere. With the little exception the authorization algorithm checks fidelity of login/password and fidelity of the session data and then it either redirects a user to the entrance page or takes massive (object) with user’s details.

Cases when session work is necessary are rare enough. For example, in my ‘Monopolist’ game I started using sessions at once because user can play some games and the same page in the same work seance may contain different data. There it’s better to save data for one of the games in which user takes part in a session and make a page for transition between the games.

I don’t assert that there’s no need in sessions. You need them but on the proper place. I’ll return later to the question of applying three authorization methods: through the 401st heading ("realm"), cookies and sessions. I’ll tell you about sessions first.

In fact, PHP sessions aren’t an authorization method (the idea itself is wrong but on forums is frequently asked a question ‘How to authorize a user through sessions?’). Integrated into PHP mechanism of users’ sessions only identifies these users; authorization is the work for your script.

I’m not going to talk much about sessions’ mechanism – all this is already done. In its simplest form (to be more exact, in the most defaulted one) this mechanism works so: the system keeps session file containing all variables on the server. By starting a session user gets a unique identifier (usually through cookie) and sends it when addressing to other pages. By starting session mechanism in your script the PHP processor checks if the file corresponding to the incoming session identifier really exists. If it exists, the script will be able to read all the data from the file; if not- a new session will be started and a file created. It’s clear that name of the given variable is defined in the PHP settings.

Now about functions we use.

session_start(). Starts session mechanism itself. A user should give variable and a file corresponding to it. If there isn’t any file, it is created and the session is restarted. If we have neither file nor variable, variable is generated (for example, heading with cookie is sent) and file is created.

session_register(name1,name2,name3…). Indication of the variables to memorize in the file after the script’s work finishes. After a user moves to another page, it’s possible to start sessions’ mechanism and after calling out given function the variables will be available.

session_destroy(). Deletes file containing session data (using cookies you are to delete them by hand with insertion of an empty cookie: "setcookie(session_name())").

session_end(). If you don’t need to change user’s details after authorization, you’d better ‘switch off the light’ at once- close the file and make free access to it.

session_set_cookie_params(life, path, domain).Setting up cookie’s parameters with session identifier (on default a cookie is set on the root of the server and on 0 seconds – until the browser shuts).

That’s all by now. There will be single detailed issues about sessions. Meanwhile I’ll describe authorization mechanism and user’s identifications by means of sessions.

So we have three files – login (login), authorization (auth) and logout (logout).

// deleting all undesirable symbols 
$login = preg_replace("/[^\w_\.\-]/", "", $HTTP_POST_VARS["login"]);
$pass = trim($HTTP_POST_VARS["pass"]);

// variables authorization 
if (strlen($login)==0 || strlen($pass)==0)
  $error = "Enter login and password ";
else {

  // login and password authorization 
  $user_result = mysql_query("SELECT * FROM user WHERE 
    login="$login" AND pass="". md5($pass). "'");
  /* if an error in the base appeared (for example, user inserted very long variable 
  into the session which the base couldn’t process) 
  or more than one string came in, we redirect the user */
  if (mysql_error())
    die(mysql_error());

  elseif (@mysql_num_rows($user_result) != 1)
    $error = "Invalid user’s name or password. ";

  // if everything is all right, we select data and start a session
  else {
    $user = mysql_fetch_assoc($user_result);

    session_set_cookie_params(1800, "/");
    session_start();

    // memorize user’s details
    session_register("user");

    // and then redirect him somewhere
    if (isset($HTTP_POST_VARS["return"]))
      header("Location: {$HTTP_POST_VARS["return"]}");
    else
      header("Location: /");
    exit();
    };
  };

/* here the user hasn’t passed authorization but he can send a cookie from the secret session; we free it. */
if (isset($HTTP_COOKIE_VARS[session_name()]))
  setcookie(session_name());

// then we draw a form; that’s not interesting. 

The given script is the data processor and the form for data input at the same time. Obtaining login and password it processes them and if they are valid, it finishes working having redirected user to the necessary page. If the data is invalid or absent, it draws a form.

/* we kill user variable in order to exclude possibility of sending data in post-request having drawn a form. */
unset($user);

//flag "session error " — if it is switched on, work stops. 
$session_error = false;

// if there isn’t any cookie with session identifier, raise a flag  
if (!isset($HTTP_COOKIE_VARS[session_name()]))
  $session_error = true;

// if such cookie exists, we start session mechanism and register $user variable. 
else {
  session_start();
  session_register("user");
  
  /* if there is no login and password in the massive, the work will also stop 
  (‘we don’t know anything, we haven’t given them to you’) */
 
  if (!isset($user["login"]) || !isset($user["pass"]))
    $session_error = true;
  };

/* if the user managed to evade errors, checking through the base is done in the same way as by entrance. */
if (!$session_error) {
  $check_result = mysql_query("SELECT uid FROM user WHERE 
    login="{$user[login]}" AND pass="{$user[pass]}"");

  if (mysql_error() || @mysql_num_rows($user_result) != 1)
    $session_error = true;
  };

// if some error appeared 
if ($session_error) {
  
  //destroy session data 
  session_destroy();

  //destroy cookie in case it existed
  if (!isset($HTTP_COOKIE_VARS[session_name()]))
    setcookie(session_name(),"","/");

  /* redirect user to the entrance with possibility to return to the address required */
  header("Location: /login.php?return=$REQUEST_URI");

  // finish the work
  exit();
  };

mysql_free_result($check_result);

User is checked in and the $user massive contains all the data about him so, for example, it’s possible to greet him by name:

<?
include("auth.inc");
?><html>
<head><title><? print ("Welcome, {$user[fname]} {$user[sname]}!"); ?></title></head>
<body>
[skip]

And output:

if(isset($HTTP_COOKIE_VARS[session_name()])) {

  // starting session mechanism
  session_start();

  // deleting file
  session_destroy();

  // deleting cookie
  setcookie(session_name());
  };

// logout from the page 
header("Location: /login.php");

Some remarks: the part which is closed with the password is in the given case the whole server (for example, service.firm.com), to close directory you are to correct paths. session_name() is used instead of PHPSESSID in order to change identifier’s name freely. By the way, it’s possible to make different session identifiers’ names on one physical server; for this it’s enough to put file .htaccess containing string php_value session.name "ABRACADABRA" into necessary part.


 

  • Top