Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP sessions lost between pages - behaves differently depending on server

I have spent a couple of months developing an application on a domain of mine. It's overall a simple concept. During development I hosted it myself on my own domain, but recently pushed it to our actual one. The problem is that sessions aren't created or kept between pages, and I can't for the life of me figure out why.

Apologize for the wall of code below, but I prefer it over a theoretical explanation.

Lets start with how I start my session at the top of every page:

function sec_session_start() {
    $session_name = 'login';
    $secure = false;
    $httponly = true;

    ini_set('session.use_only_cookies', 1);
    session_set_cookie_params(86400, '/', '.domain.com', $secure, $httponly); 
    session_name($session_name);
    session_start();
    session_regenerate_id();
}

And then how I check if the user is logged in. I added return x; instead of false for debugging. I append this to the redirect URL.

function login_check($mysqli) {
if(isset($_SESSION['id'], $_SESSION['login_string'], $_SESSION['type'])) {
    $id = $_SESSION['id'];
    $login_string = $_SESSION['login_string'];

    $user_browser = $_SERVER['HTTP_USER_AGENT'];

    if($_SESSION['type'] == 1 || $_SESSION['type'] == 2) // Admin user
    {

        if ($stmt = $mysqli->prepare("SELECT `password` FROM `users` WHERE `id` = ? LIMIT 1")) { 
            $stmt->bind_param('s', $id);
            $stmt->execute();
            $stmt->store_result();

            if($stmt->num_rows == 1) {
                $stmt->bind_result($password);
                $stmt->fetch();
                $login_check = hash('sha512', $password.$user_browser);
                if($login_check == $login_string) {
                    return true;
                } else {
                    return 1;
                }
            } else {
                return 2;
            }
        } else {
            return 3;
        }
    } else if($_SESSION['type'] == 3) { // Standard user
        if($stmt=$mysqli->prepare("SELECT `password` FROM `proj` WHERE `id` = ? LIMIT 1"))
        {
            $stmt->bind_param("s", $_SESSION['id']);
            $stmt->execute();
            $stmt->store_result();

            if($stmt->num_rows == 1)
            {
                $stmt->bind_result($db_key);
                $stmt->fetch();
                $login_check = hash('sha512', $db_key.$user_browser);
                if($login_check == $login_string) {
                    return true;
                } else {
                    return 4;   
                }
            }
        }
    } else {
        return 5;   
    }
} else {
     return 6;
}
}

I have two login pages, one for admins and one for users.

Admin:

<?php

ini_set('display_errors','On');
error_reporting(E_ALL);

include_once "../functions.php";
include_once "../db_connect.php"; 

sec_session_start();

if(login_check($mysqli) === true) {

header('Location: ../index.php');

}
else
{

// Login form

}

Users:

<?php

ini_set('display_errors','On');
error_reporting(E_ALL);

include_once "../functions.php";
include_once "../db_connect.php"; 

sec_session_start();

if(login_check($mysqli) === true) {

header('Location: ../index.php');

}
else
{

// Login form

}

Quite identical, apart from the file sources as the admin login.php is located in /admin. Despite this, the first one displays the login form correctly while the second redirects you to index.php (even when in incognito, a mystery to me), causing a redirect loop (as index.php sends it back for nog being logged in).

In addition to this, when I login with proper credentials, it does direct me to index.php only to redirect me back to login.php with error code 6.

Please do comment if you want more information or code examples, I feel lost in my own project right now.

Any help is appreciated, Thank you

UPDATE 17 dec:

After a few hours of debug, we've concluded that the issue is not with the code but with the server configuration. A simple example:

<?php

session_start();
echo session_id();

?>

If you open this file on the production server, and refresh the page, it displays a new session id with every request. I currently have no clue why. I have confirmed the session file is created as well as the cookie. It contains the proper information and can be accessed by SSH with server permissions. Truly some strange behavior.

Any clues?

like image 292
Fredrik Avatar asked Dec 11 '15 11:12

Fredrik


People also ask

What does PHP use to track sessions between the client and server?

Sessions use cookies to identify remote clients. That means that Sessions won't work if the client's web browser doesn't accept cookies. PHP keeps Sessions' data inside files.

Is PHP session server side?

Yes, the session data is on the server only.

Do I need to use session_start on every page?

It must be on every page you intend to use. The variables contained in the session—such as username and favorite color—are set with $_SESSION, a global variable. In this example, the session_start function is positioned after a non-printing comment but before any HTML.

Is PHP session case sensitive?

And, variable names are case-sensitive in PHP, unlike function names.


2 Answers

I have gone through your code and I didn't find any thing unusal except only 1 thing.

You should never use == for string comparison === is OK.

$something = 0;
echo ('password123' == $something) ? 'true' : 'false';

Run the above code and you will find the reason of your session lost. In your function login_check you are using == for comparing two string

 if($login_check == $login_string)

replace it with:

 if($login_check === $login_string)

Else every thing is absolutly fine. If changing this little thing doesn't resolve your problem then just let me know.

Advice

You are connecting to DB before session start. I would recommend you to import your function then start your session and then connect to your database.

include_once "../functions.php";
sec_session_start();
include_once "../db_connect.php"; 
like image 177
Vineet1982 Avatar answered Sep 21 '22 19:09

Vineet1982


Check if the session has already started and ensure it is only done once:

With PHP >= 5.4:

function sec_session_start() {
    if (session_status() == PHP_SESSION_NONE) {
        $session_name = 'login';
        $secure = false;
        $httponly = true;

        ini_set('session.use_only_cookies', 1);
        session_set_cookie_params(86400, '/', '.domain.com', $secure, $httponly); 
        session_name($session_name);
        session_start();
        session_regenerate_id();
    }
}

Prior to PHP 5.4:

function sec_session_start() {
    if (session_id() == '') {
        $session_name = 'login';
        $secure = false;
        $httponly = true;

        ini_set('session.use_only_cookies', 1);
        session_set_cookie_params(86400, '/', '.domain.com', $secure, $httponly); 
        session_name($session_name);
        session_start();
        session_regenerate_id();
    }
}

Additionally, why does the session have to be regenerated everytime?

like image 36
Jan Avatar answered Sep 21 '22 19:09

Jan