PHP sessions system crashes - php

I created a relatively small php/mysql based website and hosted it on a server running Red Hat 6.4, Apache/2.2.15. In order to access the site, the users are required to authenticate.
Now comes the weird problem. When I start the server, the site initially runs fine, but after about 12-24 hours, the php sessions stop working. When users try to login, their credentials a successfully retrieved from the database and the login script sets up the session variables, but when they are redirected to the home page - the session variables are lost so the home page thinks they aren't logged in and they are redirected back to the login page. The site is not heavily used, there are about 50 registered users and there are under 100 logins daily. Also, the site requires an invitation code to register, so the probability for bots to be on the site is very small.
Below are the PHP functions used to start a session, to log the users in and to check if they are authenticated (the code was inspired from http://www.wikihow.com/Create-a-Secure-Login-Script-in-PHP-and-MySQL):
function SecSessionStart() {
$session_name = 'sec_session_id'; // Set a custom session name
$secure = false;//https is not enforced
// This stops JavaScript being able to access the session id.
$httponly = true;
// Forces sessions to only use cookies.
if (ini_set('session.use_only_cookies', 1) === FALSE) {
header("Location: ../error.php?err=Could not initiate a safe session (ini_set)");
exit();
}
// Gets current cookies params.
$cookieParams = session_get_cookie_params();
session_set_cookie_params($cookieParams["lifetime"],
$cookieParams["path"],
$cookieParams["domain"],
$secure,
$httponly);
// Sets the session name to the one set above.
session_name($session_name);
session_start(); // Start the PHP session
session_regenerate_id(); // regenerated the session, delete the old one.
}
function Login($username, $password) {
$username=trim($username);
if (CheckUserCredentials($username, $password))
{
$userId=GetUserIdByUsername($username);
$hashedPass=hash("sha512",$password);
$user_browser = $_SERVER['HTTP_USER_AGENT'];
$_SESSION['user_id'] = $userId;
// XSS protection as we might print this value
$username = strtolower($username);
$_SESSION['username'] = $username;
$_SESSION['login_string'] = hash('sha512', $hashedPass.$user_browser);
// Login successful.
session_write_close();
return true;
}
else {
session_write_close();
return false;
}
}
function LoginCheck() {
// Check if all session variables are set
if (isset($_SESSION['user_id'], $_SESSION['username'], $_SESSION['login_string']))
{
$user_id = $_SESSION['user_id'];
$login_string = $_SESSION['login_string'];
$username = $_SESSION['username'];
// Get the user-agent string of the user.
$user_browser = $_SERVER['HTTP_USER_AGENT'];
$hash=GetPasswordHashByUserId($user_id);
if ($hash==null)
{
session_destroy();
session_write_close();
return false;
}
$login_check = hash('sha512', $hash.$user_browser);
if ($login_check == $login_string) {
// Logged In
session_write_close();
return true;
} else {
// Not logged in
session_destroy();
session_write_close();
return false;
}
}
session_destroy();
session_write_close();
return false;
}
In order to test my assumption that the problem was related to the sessions, I made the following php page and I've set up monitoring on it once every 5 minutes on an uptime checker:
<?php
require_once("include/authentication.php");
SecSessionStart();
$_SESSION['sessionCheck'] = "The cookie was successfully saved and retrieved";
session_write_close();
$_SESSION['sessionCheck']="";
SecSessionStart();
if (isset($_SESSION['sessionCheck']))
{
echo($_SESSION['sessionCheck']);
}
session_destroy();
session_write_close();
?>
Just as I suspected, the page returned the right answer for about 20 hours then I got an alert that the page was not displaying the success string. After I got the alert the login part on the site didn't work, either. I've tried to restart the httpd process to bring back to life the sessions, but this did not help. Only after a complete server restart things got back to normal.
I have tried searching on SO and other sites for my problem and I found some questions that were somehow related, but they did not entirely fit my situation. The main difference between my problem and other similar ones its that the site works perfectly fine in the beginning, but after some time the sessions fail all of the time. Other posters had problems where they lost sessions from time to time or the sessions did not work at all.
Any hint on the possible source of this problem would be kindly appreciated. If you need any further information from me that could help, please let me know.
Thank you

Related

PHP $-SESSION variables disappear on new page and return empty

I'm having an issue with the Sessions Variables. Ever since i switched from mysqli to PDO. It worked fine with mysqli, but ever since i switched to PDO, this issue has now come forward.
I'm trying to login and i have an area, where i want to make sure that the user can only see, if the user is logged in. The login works fine, but as soon as i get referred to my index file, i don't see anything, because of the logged in function. I can see the $_SESSION Variable gets filled, but as soon as i redirect to another file, the $_SESSION Variables disappear and i get an empty Array:
Array
(
)
process_login.php
require_once('../inc/user.inc.php'); // here i have all my functions
$user = new User(); // New Instance of my User Class
$user -> sec_session(); // selfmade session function. I use start_session() in this function
if (isset($_POST['email'], $_POST['p'])) {
$email = filter_var($_POST['email'], FILTER_SANITIZE_STRING);
$password = filter_var ($_POST['p'], FILTER_SANITIZE_STRING);
$login = $user -> login_user($email, $password);
if ($login) {
// Login sucessful
//print("<pre>".print_r($_SESSION,true)."</pre>"); //Here i get my $_SESSION variable printed out and it works. I see it is filled.
header('Location: ../index.php');
exit();
}
index.php
<?php
$title = 'Index';
$currentPage = 'Dashboard';
include('php/head.php');
require_once('../inc/user.inc.php');
$user = new User();
$user -> sec_session(); // here i call my session function again. Note: session_start() is included in this function
print("<pre>".print_r($_SESSION,true)."</pre>"); //Now The Array is empty?!?
?>
user.inc.php - sec_session function
protected function sec_session() {
$session_name = 'sec_session_id';
$secure = SECURE;
$httponly = true;
if (ini_set('session.use_only_cookies', 1) === FALSE) {
header("Location: ../error.php?err=Could not initiate a safe session (ini_set)");
exit();
}
$cookieParams = session_get_cookie_params();
session_set_cookie_params($cookieParams["lifetime"],
$cookieParams["path"],
$cookieParams["domain"],
$secure,
$httponly);
session_name($session_name);
session_start();
session_regenerate_id();
}
Whilst logging in, i set the Session to the following in my login function:
if ($db_password == $password) {
$user_browser = $_SERVER['HTTP_USER_AGENT'];
$user_id = preg_replace("/[^0-9]+/", "", $user_id);
$_SESSION['user_id'] = $user_id;
$username = preg_replace("/[^a-zA-Z0-9_\-]+/",
"",
$username);
$_SESSION['username'] = $username;
$_SESSION['login_string'] = hash('sha512',
$password . $user_browser);
return true;
}
This above works all fine, but only disappears, when i land in my index.php and i know there is something worng, but i have no idea what it is.
Are you using http or https to access your local site? If you are using secure cookies PHP won't read them under http instead it starts a new session with a new cookie, switching to https solves this problem.
It looks from your sec_session function that you are using secure cookies ($secure = SECURE;) so is your browser session using HTTPS? If you are using HTTP with secure cookies you will start a new session on each page and won't have access to existing session variables.
The best solution is to access your local site with https just like you would for your live site but if you switch off the secure cookie setting for your local site that will work too.

How to authenticate securely by session tokens and cookies? updated

I tried to write my own authentication method (school project), and I'm stuck.
Please advise, how to solve a secure authentication:
There is an index.php which contains everything that needs to be "protected". I will copy the relevant parts of my code here.
updated index.php
session_start();
function checkUserAuth(){
$authStatus = false;
if (isset($_SESSION['PHPSESSID'])){
if ($_SESSION['PHPSESSID'] == $_COOKIE['PHPSESSID']){
$authStatus = true;
}
}
return $authStatus;
}
if(!checkUserAuth()){
include_once(dirname(__DIR__).'/admin/authentication/login.php');
exit();
}
If the checkUserAuth() determines, that there is no properly authenticated user, will include the login.php and stop the rest of the script.
updated login.php:
if(array_key_exists($username, $users) && password_verify($password, $users[$username])){
$_SESSION['PHPSESSID'] = $_COOKIE['PHPSESSID'];
$_SESSION['login_user'] = $_POST['user'];
What I imagine that might happen, is that if the login details are correct, the login.php sets a cookie, and refreshes the page. Then the index.php will detect the cookie, and skip the login part.
The login is pretty much figured out, and thanks to Juned, I think it is working now. However I don't know how secure is this?
On a scale from 1 to very, how wrong I am?
There are loads of ways of doing this. The below pseudocode is not the most efficient but should work and I don't think what you've done above will actually work.
Does this help?
login.php pseudocode
<?php
session_start(); // this function checks if there's a session ID already set, if not, sets one.
if(array_key_exists($username, $users) && password_verify($password, $users[$username])){
// do your login details checking here
// if login details correct
// set a flag in the $_SESSION superglobal and whatever else you want to store about the user like their username e.g.
$_SESSION["loggedIn"] = true;
$_SESSION["username"] = "$_POST['user']"; // better practice to fetch a clean version from your database
//else return user to login page
}
?>
index.php pseudocode
<?php
session_start(); // this will fetch the session ID and other variables that you might have set e.g. username, logged in status
function checkUserAuth(){
$authStatus = false;
if (isset($_SESSION['loggedIn']) && $_SESSION['loggedIn'] === true){
$authStatus = true;
}
return $authStatus;
}
if(!checkUserAuth()){
// redirect to login page. e.g.
header('Location: login.php');
exit;
}
?>

$_SESSION cookies not expiring when browser is closed

So here is my code that sends an expire time of a year if remember me is clicked.
And if not, then it sets the session_set_cookie_params() to 0. Which means that it should destroy the session when browser is closed. However it isn't working like that for some reason.
This is my login page:
session_start();
if (isset($_POST['username']) && isset($_POST['password'])) {
if (($_POST['username'] == $user) && ($_POST['password'] == $pass)) {
if (isset($_POST['rememberme'])) {
$_SESSION['username'] = $user;
$_SESSION['start'] = time();
$_SESSION['expire'] = $_SESSION['start'] + (60*60*24*365);
}
else{
$_SESSION['username'] = $user;
session_set_cookie_params(0);
}
header('Location: index.php');
} else {
$p->addContent('<font color = red>Wrong</font>');
}
}
This is my index page:
session_start();
if (isset($_POST['rememberme'])){
$user = $_SESSION['username'];
}
else {
$user = $_SESSION['username'];
session_set_cookie_params(0);
}
if ($user == null) {
$user = 'Guest';
$logout = $p->header()->addButton('Login', 'login.php', 'a', 'home', false, false, true);
$logout->rel('external');
}
else{
$logout = $p->header()->addButton('Logout', 'logout.php', 'a', 'delete', false, false, true);
$logout->rel('external');
}
It's quite simple. session_set_cookie_params(0); isn't affecting your session as you call it after calling session_start();.
Just reorder your code to something like this:
if (isset($_POST['username']) && isset($_POST['password'])) {
if (($_POST['username'] == $user) && ($_POST['password'] == $pass)) {
if (isset($_POST['rememberme'])) {
session_start();
$_SESSION['username'] = $user;
$_SESSION['start'] = time();
$_SESSION['expire'] = $_SESSION['start'] + (60*60*24*365);
} else {
session_set_cookie_params(0);
session_start();
$_SESSION['username'] = $user;
}
header('Location: index.php');
} else {
session_start();
$p->addContent('<font color = red>Wrong</font>');
}
} else {
session_start();
}
EDIT:
It's also worth nothing that session_set_cookie_params only work on the current script and has to be called again every time you use session_start(). It might me useful to set a cookie to indicate if it should used.
As of your code, session_set_cookie_params() isn't called in any case. Therefore I propose to do this:
session_set_cookie_params(0);
session_start();
if (isset($_POST['username']) && isset($_POST['password'])) {
...
Note, that's actually useful to call session_set_cookie_params() always for session cookies.
Generate a new session-ID at each user level change
To protect your applications against attackers, it is absolutely required to change the sessionID after each change of the role of a user:
Anonymous user -> Logged in user
Logged in user -> anonymous user
Logged in user -> Administrative logged in user
...
Thus, if user gets logged in or logged off, please regenerate the session ID like so:
session_regenerate_id( true );
Have a look in OWASP's PHP security cheat sheet.
Session-files get deleted regularly
Using PHP's standard session policy, sessions get mapped to regular files, so called session-files. If the user closes his browser, the session-file keeps living in the file system. Quite likely, the operation system is going to delete the session-file once a day (by night).
Thus, if a user comes back a day later, the sessionID cookie points to a session-file, which might no longer be available.
The case of public PCs
Additionally imagine a browser running on a public PC: If user closes his browser and a new user logs in, the other user gets automatically logged in.

How to login with one ID/Pass from one computer at a time only

I have a PHP website with signup/login system. For security reasons, I want that the users are only able to sign in from one PC at a time. If same ID/Password tries to sign in from another PC while a user is already logged in with that ID/Password, it should generate an error message.
Please tell me how it is possible and what is the best way to do it?
I am using only cookies...
<?php function sec_session_start() {
$session_name = 'sec_session_id'; // Set a custom session name
$secure = false; // Set to true if using https.
$httponly = true; // This stops javascript being able to access the session id.
ini_set('session.use_only_cookies', 1); // Forces sessions to only use cookies.
$cookieParams = session_get_cookie_params(); // Gets current cookies params.
session_set_cookie_params($cookieParams["lifetime"], $cookieParams["path"], $cookieParams["domain"], $secure, $httponly);
session_name($session_name); // Sets the session name to the one set above.
session_start(); // Start the php session
session_regenerate_id(true); // regenerated the session, delete the old one.
}
Here is the code:
if(login($name, $password, $mysqli) == true) {
// Login success
if($name == 'admin'){
if($signin == 'zero'){
$stmt = $mysqli->prepare("UPDATE users SET signin = 'one' WHERE name = 'admin'");
$stmt->execute();
?>
<span class="TextFont"><br /><br />Welcome Admin! Click here to access your Admin Panel! <br /><br /> Logout</span>
<?php }
else{
echo"You are already logged in from some other system! $signin";
}}
else{
// some PHP code
}
else{
// some PHP code
}
if you also add a column session_id in the user table and you store sessions in a database (even more secure) You also could check more easier if user sessions are expired to update the signin column to 0 again and this is more waterproof against users that don't use a signout feature... (upgraded jycr753 solution)
What has worked for me in the past is this.
Add a column to your user table to store the session id.
When a user authenticates update the user record with the session for login.
When you are checking to see if a request is authenticated or not search the database for the user's session id.
Note with session_regenerate_id occuring on each page you will have to update the user record with each request, an alternative would be to store a unique value within the session and have that updated on the user record and confirm an authenticated request by matching values of that.
In pseudo-code
session_start();
session_regenerate_id();
if ($_SESSION["session_key"]);
$user = UserStore::getUserBySessionKey($_SESSION["session_key"]);
if ($user){
// the request is authenticated
} else {
// redirect to the login page
}
And on Login
session_start();
session_regenerate_id();
$user = UserStore::authenticateUser($username, $password);
if ($user){
$sessionKey = uniqid().$user->username;
$user->setSessionkey($sessionKey);
$user->save();
$_SESSION["session_key"] = $sessionKey;
} else {
// show the login form with an error
}

Session variables not carrying to next page

I've just begun using sessions and am having some headaches, I had this working last night, now opening it today...no longer works.
In my login processor I have the following if everything is OK. This script works fine, I have echoed the session variables to ensure that the array works, and it does.
$username - > post from login script
$encrypt_password -> created from password check further up the script
{
$session_name = 'LOGIN'; // Set a custom session name
$secure = false; // Set to true if using https.
$httponly = true; // This stops javascript being able to access the session id.
$cookie_lifetime = '3600';
$cookie_path = '/';
$cookie_domain = '127.0.0.1';
session_set_cookie_params($cookie_lifetime, $cookie_path, $cookie_domain, $secure, $httponly);
session_name($session_name); // Sets the session name to the one set above.
$group = $row['group_type'];
$user_browser = $_SERVER['HTTP_USER_AGENT']; /*grabs browser info*/
$user_id = preg_replace("/[^a-zA-Z0-9_\-]+/", "", $username); /*XSS Protection*/
$group_id = preg_replace("/[^a-zA-Z0-9_\-]+/", "", $group); /*XSS Protection*/
session_start();
$_SESSION['user']=$user_id;
$_SESSION['group_name']=$group_id;
$_SESSION['login_string'] = hash('sha512', $user_browser.$encrypt_password);
session_write_close();
header("location:".$group_id."_index.php");
}
I have created an include file which gathers the info from the session, included on every protected page, this is where it fell apart. I have created custom error codes for each if statement and have found that the if statement here fails. Echoing the session variables or evening printing the session array returns nothing.
$session_name = 'LOGIN'; // Set a custom session name
$secure = false; // Set to true if using https.
$httponly = true; // This stops javascript being able to access the session id.
$cookie_lifetime = '3600';
$cookie_path = '/';
$cookie_domain = '127.0.0.1';
session_set_cookie_params($cookie_lifetime, $cookie_path, $cookie_domain, $secure, $httponly);
session_name($session_name); // Sets the session name to the one set above.
session_start(); // Start the php session
session_regenerate_id(false); // regenerated the session, delete the old one.
if(isset($_SESSION['user'],$_SESSION['group_name'], $_SESSION['login_string']))
I was changing around the way the user groups worked before this broke, however none of the variables make it through. I am learning from his tut by the way: create a secure login script in php and mysql
Also do I need to call the session parameters every time a user visits a protected page?
Thanks in advance for any pointers.
Try putting session_start(); on TOP of everything, most importantly before you're calling a session. You're calling session_name($session_name); before it even started.
it=session
your regenerating the session on every page, which causes the previous session to destroy data.
remove session_regenerate_id(false);

Categories