Jump to content
  • Advertisement
Sign in to follow this  
b1gjo3

php session manager help

This topic is 2122 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello gamedev
 
I'm currently trying to implement a secure login script using https, mysql and sesssions. I've been following this guide from here to manage sessions:
 
http://www.wikihow.com/Create-a-Secure-Session-Managment-System-in-PHP-and-MySQL
 

My problem is that my session data is not being stored from my login script (in logindb.php). The session_id is changing on every single page load and encrypts the data coming in/out to db and I'm not sure if this is whats causing the data to not carry over to next page load.

 

I've been debugging for a while now and cannot seem to come to a solution. I think maybe I just don't understand how sessions work. Sorry for the long post, I've included my code below for anyone who wants to help me look over it for any issues.

 

Much appreciated

 

./inc/logindb.php

 
<?php
 
require_once('session.class.php');
$session = new session();
$session->start_session('_s', true);
 
function login($email, $password, $mysqli) {
// Using prepared Statements means that SQL injection is not possible. 
    if ($stmt = $mysqli->prepare("SELECT uid, username, password, salt FROM login_ids WHERE email = ? LIMIT 1")) { 
    $stmt->bind_param('s', $email); // Bind "$email" to parameter.
       $stmt->execute(); // Execute the prepared query.
       $stmt->store_result();
       $stmt->bind_result($uid, $username, $db_password, $salt); // get variables from result.
       $stmt->fetch();
       
       //echo "session: " . session_id() . "<br>";
       //echo "uid: " . $uid . "<br>";
        //echo "pw: " . $password . "<br>";
       //echo "db: " . $db_password . "<br>";
       $password = hash('sha512', $password.$salt); // hash the password with the unique salt.
       //echo "salt: " . $salt . "<br>";     
       //echo "pw-salt: " . $password . "<br>";
       
       if($stmt->num_rows == 1) { // If the user exists
         // We check if the account is locked from too many login attempts
          if(checkbrute($uid, $mysqli) == true) { 
             // Account is locked
             // Send an email to user saying their account is locked
             return false;
          } else {
          if($db_password == $password) { // Check if the password in the database matches the password the user submitted. 
          // Password is correct!
                $user_browser = $_SERVER['HTTP_USER_AGENT']; // Get the user-agent string of the user.
 
               $uid = preg_replace("/[^0-9]+/", "", $uid); // XSS protection as we might print this value
                 $_SESSION['uid'] = $uid; 
                 $_SESSION['username'] = $username;
                 $_SESSION['login_string'] = hash('sha512', $password.$user_browser);
                 // Login successful.
               return true;    
          } else {
             // Password is not correct
             // We record this attempt in the database
             $now = time();
             $mysqli->query("INSERT INTO login_attempts (uid, time) VALUES ('$uid', '$now')");
             return false;
          }
       }
       } else {
         // No user exists.
          return false;
       }
}
}
 
function checkbrute($uid, $mysqli) {
$valid_attempts = time() - (2 * 60 * 60);
 
if ($stmt = $mysqli->prepare("SELECT time FROM login_attempts WHERE uid = ? AND time > '$valid_attempts'")) {
$stmt->bind_param('i', $uid);
 
// Execute the prepared query.
$stmt->execute();
$stmt->store_result();
// If there has been more than 5 failed logins
if($stmt->num_rows > 5) {
return true;
} else {
return false;
}
}
}
 
function login_check($mysqli) {
// Check if all session variables are set
if(isset($_SESSION['uid'], $_SESSION['username'], $_SESSION['login_string'])) {
$uid = $_SESSION['uid'];
$login_string = $_SESSION['login_string'];
$user_browser = $_SERVER['HTTP_USER_AGENT']; // Get the user-agent string of the user.
 
if ($stmt = $mysqli->prepare("SELECT password FROM login_ids WHERE uid = ? LIMIT 1")) {
$stmt->bind_param('i', $uid); // Bind "$user_id" to parameter.
$stmt->execute(); // Execute the prepared query.
$stmt->store_result();
 
if($stmt->num_rows == 1) { // If the user exists
$stmt->bind_result($password); // get variables from result.
$stmt->fetch();
$login_check = hash('sha512', $password.$user_browser);
if($login_check == $login_string) {
// Logged In!!!!
return true;
} else {
// Not logged in
return false;
}
} else {
// Not logged in
return false;
}
} else {
// Not logged in
return false;
}
} else {
// Not logged in
return false;
}
}
?> 

./inc/session.class.php

// file - session.class.php
<?php 
 
class session {
 
function start_session($session_name, $secure) {
// Make sure the session cookie is not accessable via javascript.
$httponly = true;
 
   // Hash algorithm to use for the sessionid. (use hash_algos() to get a list of available hashes.)
   $session_hash = 'sha512';
 
   // Check if hash is available
   if (in_array($session_hash, hash_algos())) {
     // Set the has function.
       ini_set('session.hash_function', $session_hash);
   }
   // How many bits per character of the hash.
   // The possible values are '4' (0-9, a-f), '5' (0-9, a-v), and '6' (0-9, a-z, A-Z, "-", ",").
   ini_set('session.hash_bits_per_character', 5);
 
   // Force the session to only use cookies, not URL variables.
   ini_set('session.use_only_cookies', 1);
 
   // Get session cookie parameters 
   $cookieParams = session_get_cookie_params(); 
   // Set the parameters
   session_set_cookie_params($cookieParams["lifetime"], $cookieParams["path"], $cookieParams["domain"], $secure, $httponly); 
   // Change the session name 
   session_name($session_name);
   // Now we cat start the session
   session_start();
   // This line regenerates the session and delete the old one. 
   // It also generates a new encryption key in the database. 
   session_regenerate_id(true);    
}
 
function __construct($secure = false) {
 
// set our custom session functions.
session_set_save_handler(array($this, 'open'), 
array($this, 'close'), array($this, 'read'), 
array($this, 'write'), array($this, 'destroy'), 
array($this, 'gc'));
 
// This line prevents unexpected effects
// when using objects as save handlers.
register_shutdown_function('session_write_close');
}
 
function open() {
$host = 'localhost';
$user = 'sec_user';
$pass = 'f3HZqVGADvYsnvjA';
$name = 'secure_sessions';
$session_mysqli = new mysqli($host, $user, $pass, $name);
$this->db = $session_mysqli;
return true;
}
 
function close() {
$this->db->close();
return true;
}
 
// prepare statement (read_stmt) to be executed on db
// param: $id - session id stored in db
function read($id) {
if(!isset($this->read_stmt)) {
$this->read_stmt = $this->db->prepare("SELECT data FROM sessions WHERE id = ? LIMIT 1");
}
$this->read_stmt->bind_param('s', $id);
$this->read_stmt->execute();
$this->read_stmt->store_result();
$this->read_stmt->bind_result($data);
$this->read_stmt->fetch();
$key = $this->getkey($id);
echo "read: \"" . $data . "\"<br>decrypted: ";
$data = $this->decrypt($data, $key);
echo $data . "<br>";
return $data;
}
 
// prepare statement (w_stmt) to be executed on db
function write($id, $data) {
if ($data == null)
return false;
 
// Get unique key
$key = $this->getkey($id);
// Encrypt the data
echo "write: " . $data . "<br>crypted: ";
$data = $this->encrypt($data, $key);
echo $data . "<br>";
 
$time = time();
if(!isset($this->w_stmt)) {
$this->w_stmt = $this->db->prepare("REPLACE INTO sessions (id, set_time, data, session_key) VALUES (?, ?, ?, ?)");
}
 
$this->w_stmt->bind_param('siss', $id, $time, $data, $key);
$this->w_stmt->execute();
return true;
}
 
// delete session
function destroy($id) {
if(!isset($this->delete_stmt)) {
$this->delete_stmt = $this->db->prepare("DELETE FROM sessions WHERE id = ?");
}
$this->delete_stmt->bind_param('s', $id);
$this->delete_stmt->execute();
return true;
}
 
//garbage collector
function gc($max) {
if(!isset($this->gc_stmt)) {
$this->gc_stmt = $this->db->prepare("DELETE FROM sessions WHERE set_time < ?");
}
$old = time() - $max;
$this->gc_stmt->bind_param('s', $old);
$this->gc_stmt->execute();
return true;
}
 
//get key from db
//creates key if no key avail
private function getkey($id) {
if(!isset($this->key_stmt)) {
$this->key_stmt = $this->db->prepare("SELECT session_key FROM sessions WHERE id = ? LIMIT 1");
}
$this->key_stmt->bind_param('s', $id);
$this->key_stmt->execute();
$this->key_stmt->store_result();
 
//check to see if result ret any rows
if($this->key_stmt->num_rows == 1) {
$this->key_stmt->bind_result($key);
$this->key_stmt->fetch();
return $key;
} else {
$random_key = hash('sha512', uniqid(mt_rand(1, mt_getrandmax()), true));
return $random_key;
}
}
 
public function __isset($var){
return isset($_SESSION[$var]);
}
 
private function encrypt($data, $key) {
$salt = 'cH!swe!retReGu7W6bEDRup7usuDUh9THeD2CHeGE*ewr4n39=E@rAsp7c-Ph@pH';
$key = substr(hash('sha256', $salt.$key.$salt), 0, 32);
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $data, MCRYPT_MODE_ECB, $iv));
return $encrypted;
}
 
private function decrypt($data, $key) {
$salt = 'cH!swe!retReGu7W6bEDRup7usuDUh9THeD2CHeGE*ewr4n39=E@rAsp7c-Ph@pH';
$key = substr(hash('sha256', $salt.$key.$salt), 0, 32);
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($data), MCRYPT_MODE_ECB, $iv);
return $decrypted;
}
}
?>

./inc/header.php

 
<?php 
//file - header.php
include 'db_connect.php';
include 'logindb.php';
 
require_once('session.class.php');
$session = new session();
 
if (!session_id())
{
if ($_SERVER["HTTPS"] != "on")
$session->start_session('_s', true);
else
$session->start_session('_s', false);
}
$_SESSION['something'] = 'a value';
echo session_id() . " : ";
print_r($_SESSION);
?>
 
<html>
 
<head>
<title>PHP Login Example</title>
<style>
<?php 
include './css/header.css'; 
include './css/signin.css';
?>
</style>
</head>
 
<body>
<div id="header">
 
<img src="./img/php_login.jpg" />
 
<div id="login-bar">
 
<?php 
echo "sid: " . session_id() . "<br>";
 
if (!login_check($mysqli)) 
echo 'not logged in ';
else
echo 'logged in';
?>
 
<ul>
<li><a href=" <?php
echo "https://" . $_SERVER["SERVER_NAME"] . "/php_login/login.php"
?>">SIGN IN</a></li>
<li> | </li>
<li><a href="#">REGISTER</a></li>
</ul>
</div>
</div> 

./inc/process_login.php

<?php
include 'logindb.php';
include 'db_connect.php';
 
if (!session_id())
session_start();
 
if(isset($_POST['email'], $_POST['password'])) { 
$email = $_POST['email'];
    $password = $_POST['password']; //not hashed due to ssl
    
    if(login($email, $password, $mysqli) == true) {
     // Login success
       //echo 'Success: You have been logged in!';
    
       header('Location: ../index.php');
    } else {
     // Login failed
       header('Location: ../login.php?error=1');
    }
} else { 
   // The correct POST variables were not sent to this page.
   echo 'Invalid Request';
}
?>

./login.php

<?php 
include './inc/header.php';
?>
<div id="sign-in">
<?php 
//check to see if logged in
 
if(isset($_GET['error'])) { 
  echo 'Error Logging In!';
}
?>
 
<form action="./inc/process_login.php" method="post" class="pw" name="login_form">
email: <input name="email" type="text">
pw: <input type="password" name="password">
<input type="submit" value="Submit">
</form> 
</div>
 
</body>
</html>
Edited by sc2bigjoe

Share this post


Link to post
Share on other sites
Advertisement

I'm not sure session_regenerate_id() properly uses whatever you have registered with session_set_save_handler. You may have to manually update the database entries that refer to the old id (at the end of start_session()).

 

What happens if you remove the session_regenerate_id() line altogether?

Share this post


Link to post
Share on other sites

thank you for replying. i tried commenting out session_regenerate_id() before and it didn't have any effect. I just tried it again and my session still regenerates on every page load.

 

i thought for a while I wasn't loading sessions on the appropriate pages correctly

$session = new session();
 
if (!session_id())
{
if ($_SERVER["HTTPS"] != "on")
$session->start_session('_s', true);
else
$session->start_session('_s', false);
}

 

but no matter how I seem to change this everything is still not working. uid, username, and login_string are still not being accessed on the next page load. So how do I refer to the old session_id() so I can update it in db?

 

thanks again!

Share this post


Link to post
Share on other sites
if (!session_id())
session_start();


If you've implemented your own handler-interface (the Session class) you shouldn't call session_start() outside of it (as you do in process_login.php), because this would circumvent your database handler and use the default serializer instead. It also would populate session_id which would cause the "if (!session_id())"-test to fail.

 

Make sure this is done for every request (a session start also implies a session-restart):

$session = new session();
 
$session->start_session('_s', $_SERVER["HTTPS"] != "on");
Edited by eppo

Share this post


Link to post
Share on other sites

that did the trick. I also had $session->start_session being called multiple times on a single page because I was including 'header.php' on everything. thank you for the help.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!