Question

There is only ever going to be 1 username and 1 password to access this page, so decided to store it within PHP itself, as it probably is more secure than storing it within the database. However, I'm trying to get a grip on sessions and hoping that:

  1. It will not compromise security in any way.
  2. It will not stop the session (for logged in user(s)) scripts from running when other people try to log in and fail. For example, I don't want it to delete the session for the logged in user. Probably a stupid question, but figured I'd ask anyways.

My index.php file for this, in php looks like this:

session_start();

if (!isset($_SESSION['Admin']))
{
    if (isset($_POST['username'], $_POST['password']) && $_POST['username'] == 'someUsername' && $_POST['password'] == 'someVeryStrongPassword')
    {
        $_SESSION['Admin'] = true;
        session_write_close();
    }
    else {
            // You don't have access, go back to login page.
        session_destroy();
        header("location:login.php");
        exit();
    }
}

// This will now be used for any subsequent, same page requests, such as:  `index.php?action={something}`, etc. but will always use `index.php` as the main page.

// Is it now safe to continue on with code assuming that the user is logged in at this point?  Should there be anything else to consider adding?  Possibly into the $_SESSION[] array?

My login.php file is just HTML really and looks like this:

<!DOCTYPE html>
<html>
<head>
<title>Administration</title>
</head>
<body>
<form name="login" method="POST" action="index.php">
    <label for="user">Username: <input id="user" type="text" name="username" /></label><br />
    <label for="pass">Password: <input id="pass" type="password" name="password" /></label><br />
    <p><input type="submit" value="Login" /></p>
</form>
</body>
</html>

Again, I am planning on attaching the $sess_id variable to all forms that get submitted within the index.php file and checking it against session_id(). Is this secure enough? Been looking at session_regenerate_id and session_id. People have reported that session_regenerate_id causes problems when multiple users are logged in (old session id vs. new session ids). Would it be wise to use session_regenerate_id at all, in my situation (since I'm not storing any data into the database)?

Updated code thanks to M Miller

Was it helpful?

Solution

First of all, I kind of learned this wrong initially. I always thought that PHP sessions were something unique and secure intrinsically. But sessions are just cookies that terminate at the end of the browser session. PHP sessions are more intelligently crafted than your average cookie, but they've got most of the same vulnerabilities and flaws. Cookies just plain aren't safe.

First of all, you should set session.use_only_cookies. Oftentimes it's easier to get an HTTP request than it is to get cookies from an unsuspecting victim. History is easier to read, and people often clear cookies without clearing history. It's also displayed on your freaking monitor, so you might as well have your URL be http://example.com/admin/index.php?username=admin&password=MyPaSsWoRd!123

You have two possible courses of action: if you use session_regenerate_id(true), you'll need to implement a system for multiple simultaneous logons -- or you can just assume that if somebody logs in from another device, everybody else's access will terminate.

I prefer an inactivity timeout, because a session lasts as long as the browser is open -- and who knows how long that will be?

You just need this logic:

On login:

<?php
$_SESSION['Admin'] = true;
$_SESSION['timeout'] = time()+3600; // +1 hour
?>

And on subsequent admin pages:

<?php
if (!isset($_SESSION['timeout']) || $_SESSION['timeout'] < time()) {
   // destroy the session
   // redirect to login
   exit;
}
?>

(If you're developing a UI, maybe you want to add a warning when the timeout approaches so that the user doesn't lose his information.)

Don't worry about putting everything on index.php, because none of that matters.

Don't rely on things like the client's OS, browser, or IP address. These are unreliable, subject to change, and can be easily spoofed. Although the IP address can't be faked (technically, not to any use), your IP address might change during the session and you could lock yourself out.

To be honest, if you're going to have multiple sign-ins from different devices at the same time, I'd avoid regenerating the session ID. If you're the only user, then use it, because it does sort of add a layer of security. The scenario is, if a session ID is obtained, the hacker only has a short window of opportunity to use the session before it is regenerated by you, the user.

Charles Miller wrote a great article about persistent authentication, and this is where I'll point you to, because this is how I learned how to do my auth: http://fishbowl.pastiche.org/2004/01/19/persistent_login_cookie_best_practice/ (Disregard the Barry Jaspan link at the bottom, it's not really any more secure, and it's needlessly more complicated.) session_regenerate_id would make implementing this system pretty easy -- and it'd be very simple if you only had one user. In fact, you could store a history of session IDs and, assuming that no session ID will ever be reused in the foreseeable future of your app (and it's highly unlikely), you could simply say that if someone tries to access your app using a previously used and now invalidated session ID, you can assume they're a hacker and act accordingly.

Here's a way to implement just that (using no database, for simplicity's sake):

<?php
$sessions = explode(PHP_EOL, file_get_contents('sessions.log'));
   // Get the history of all past sessions
if (in_array(session_id(), $sessions) {
   // The current session ID is a session that has already been discarded
   // Hijack alert!
   mail('youremail@example.com', 'HIJACK ALERT!', 'Somebody tried to use the session '.session_id().'! The bastard\'s IP was '.$_SERVER['REMOTE_ADDR'], 'From: php@server');
   session_destroy();
   echo 'Nice try, jerk! The admin has been notified....';
   exit;
}

if (isset($_SESSION['Admin']) && $_SESSION['Admin']) {
   // Logged in!
   file_put_contents('sessions.log', PHP_EOL.session_id(), FILE_APPEND);
      // Add the current session ID to a file containing a history of session IDs
   session_regenerate_id(true);
      // Regenerate the session and delete the old one
}
?>

(Untested.) Granted, this is a rather primitive example, but it might be what you need.

The best solution is, as I mentioned in the comments, HTTP authentication, so use that if it's an option.

And the last thing we talked about: hashing the password. If somebody gains access to your file server and consequently your source code, you're in trouble and your application is compromised regardless. But if you use the same password elsewhere, by all means, only store a hash of it in the source code so you can limit the damage. Then, if your password is the same as your bank account's password, at least the hacker only sees

if (hash('whirlpool', $_POST['password'].$salt) == '9923afaec3a86f865bb231a588f453f84e8151a2deb4109aebc6de4284be5bebcff4fab82a7e51d920237340a043736e9d13bab196006dcca0fe65314d68eab9')

(P.S. Whirlpool is the best hash, in my opinion. And my favorite way to salt is to split the password in half and stick the salt in the middle. Then, even if both are known and the hacker has a super hash table, he's still screwed. e.g. $half = floor(strlen($password)/2); $hash = hash('whirlpool', substr($password, 0, $half).$salt.substr($password, $half));)

OTHER TIPS

If you use only sessions there will be always a possibility that the session gets hijacked. Sessions are good but you need more protection to make it harder to get in. for example you could...

1)check if the IP address of the client changes during the session (this makes session hijacking a pain in the ass)

2)use some cookies to identify the client

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top