Click to See Complete Forum and Search --> : Is this login script secure enough?


curb
05-27-2007, 02:34 PM
I was wondering if there is any way to improve the simple login script attached for security. It's the first so I know I'm missing or doing something wrong.


mysql

CREATE TABLE users (
id int(10) DEFAULT '0' NOT NULL auto_increment,
username varchar(40),
password varchar(50),
regdate varchar(20),
email varchar(100),
website varchar(150),
location varchar(150),
show_email int(2) DEFAULT '0',
last_login varchar(20),
PRIMARY KEY(id))

<?php
//check_login.php

/* check login script, included in db_connect.php. */

session_start();

if (!isset($_SESSION['username']) || !isset($_SESSION['password'])) {
$logged_in = 0;
return;
} else {

// remember, $_SESSION['password'] will be encrypted.

if(!get_magic_quotes_gpc()) {
$_SESSION['username'] = addslashes($_SESSION['username']);
}

// addslashes to session username before using in a query.
$qry = "SELECT password FROM users WHERE username = '".$_SESSION['username']."'";
$pass = $db_object->query($qry);

if(DB::isError($pass) || $pass->numRows() != 1) {
$logged_in = 0;
unset($_SESSION['username']);
unset($_SESSION['password']);
// kill incorrect session variables.
}

$db_pass = $pass->fetchRow();

// now we have encrypted pass from DB in
//$db_pass['password'], stripslashes() just incase:

$db_pass['password'] = stripslashes($db_pass['password']);
$_SESSION['password'] = stripslashes($_SESSION['password']);

//compare:

if($_SESSION['password'] == $db_pass['password']) {
// valid password for username
$logged_in = 1; // they have correct info
// in session variables.
} else {
$logged_in = 0;
unset($_SESSION['username']);
unset($_SESSION['password']);
// kill incorrect session variables.
}
}

// clean up
unset($db_pass['password']);

$_SESSION['username'] = stripslashes($_SESSION['username']);

?>

<?php
//login.php

// database connect script.

require 'db_connect.php';

if($logged_in == 1) {
die('You are already logged in, '.$_SESSION['username'].'.');

}

?>
<html>
<head>
<title>Login</title>
</head>
<body>
<?php

if (isset($_POST['submit'])) { // if form has been submitted

/* check they filled in what they were supposed to and authenticate */
if(!$_POST['uname'] | !$_POST['passwd']) {
die('You did not fill in a required field.');
}

// authenticate.

if (!get_magic_quotes_gpc()) {
$_POST['uname'] = addslashes($_POST['uname']);
}

$qry = "SELECT username, password FROM users WHERE username = '".$_POST['uname']."'";
$check = $db_object->query($qry);

if (DB::isError($check) || $check->numRows() == 0) {
die('That username does not exist in our database.');
}

$info = $check->fetchRow();

// check passwords match

$_POST['passwd'] = stripslashes($_POST['passwd']);
$info['password'] = stripslashes($info['password']);
$_POST['passwd'] = md5($_POST['passwd']);

if ($_POST['passwd'] != $info['password']) {
die('Incorrect password, please try again.');
}

// if we get here username and password are correct,
//register session variables and set last login time.

$date = date('m d, Y');

$qry = "UPDATE users SET last_login = '$date' WHERE username = '".$_POST['uname']."'";
$update_login = $db_object->query($qry);

$_POST['uname'] = stripslashes($_POST['uname']);
$_SESSION['username'] = $_POST['uname'];
$_SESSION['password'] = $_POST['passwd'];
$db_object->disconnect();
?>

<h1>Logged in</h1>
<p>Welcome back <?php echo $_SESSION['username']; ?>, you are logged in.</p>

<?php

} else { // if form hasn't been submitted

?>
<h1>Login</h1>
<form action="<?php echo $_SERVER['PHP_SELF']?>" method="post">
<table align="center" border="1" cellspacing="0" cellpadding="3">
<tr><td>Username:</td><td>
<input type="text" name="uname" maxlength="40">
</td></tr>
<tr><td>Password:</td><td>
<input type="password" name="passwd" maxlength="50">
</td></tr>
<tr><td colspan="2" align="right">
<input type="submit" name="submit" value="Login">
</td></tr>
</table>
</form>
<?php
}
?>
</body>
</html>

<?php
//example usage

require 'db_connect.php';

if ($logged_in == 1) {
echo 'Logged in as '.$_SESSION['username'].', <a href="logout.php">logout</a>';
} else {
echo 'Not logged in. <a href="login.php">Login</a>';
}

?>

Piranha
05-27-2007, 02:44 PM
I can only speak for myself, but I can't be bothered to download, unzip and view code. I can however be bothered to view code that is in [ php] [/php] tags on these forums.

curb
05-27-2007, 02:53 PM
thanks Piranha for the tip.

NogDog
05-27-2007, 03:08 PM
Do not save the password in the $_SESSION array. It should only be submitted via the login form and used to verify the login (and if security is a high priority then, of course, the login info should all be done via SSL connection). If the password is saved in $_SESSION, then anyone else with an account on that server and able to read the directory where session data is saved could conceivably view it. You would then check to see if a user is logged in by simply checking if the $_SESSION['username'] is set.

curb
05-27-2007, 04:03 PM
When you say account, are you referring to virtual hosting or an account from that database? I will be the only user with the login.

Piranha
05-27-2007, 04:27 PM
I have just had a quick look at the code, and here is what I found:

It is a good idea to set columns to NULL or NOT NULL when creating the table. It is not about security, but it may solve a few problems later on.
Don't use addslashes, it is not reliable. Use the method for the database you are using instead, for mysql it is mysql_real_escape_string. If you have PHP version 5 or newer you should instead use mysqli_real_escape_string, and with even newer versions you should use pdo.
Don't use if(!$_POST['uname'] | !$_POST['passwd']) {It is better to see if it is empty if(empty($_POST['uname']) || empty($_POST['passwd'])) {And I don't understand why you compare bitwise, but that might not be anything.
In the form you set the value of submitting in the submit button. It won't work on some browsers when the user use return instead of clicking the button. Use a hidden field instead to solve the problem.

NogDog
05-27-2007, 04:32 PM
Any user with a server login account, either able to run a script on that server and/or able to directly log in and run OS commands. This is mainly an issue with shared hosts. The risk can be reduced by specifying your own, separate session data directory, or even better by using your own session-handler function/class that stores the session data in a database. In any case, is there any functional purpose to save the password in the session data?

More info:
Sessions and Security (http://us.php.net/manual/en/ref.session.php#session.security) (PHP manual)
Session Fixation (http://www.acros.si/papers/session_fixation.pdf) (PDF)
session_set_save_handler (http://www.php.net/session_set_save_handler)()
session_save_path (http://www.php.net/manual/en/function.session-save-path.php)()