0

I apologize in advance for a long mostly code question

When I decided to add a "remember me" button to my login form, the cookies I set aren't being loaded. I loosely based my login class off of this code:

<?php

class Login
{
  private $_id;
  private $_username;
  private $_password;
  private $_passmd5;
  private $_remember;

  private $_errors;
  private $_access;
  private $_login;
  private $_token;

  public function __construct()
  {
    $this->_errors = array();
    $this->_login  = isset($_POST['login'])? 1 : 0;
    $this->_access = 0;
    if(isset($_POST['token']))
     $this->_token  = $_POST['token'];

    $this->_id       = 0;
    $this->_username = ($this->_login)? $this->filter($_POST['username']) : $_SESSION['username'];
    $this->_password = ($this->_login)? $this->filter($_POST['password']) : '';
    $this->_passmd5  = ($this->_login)? md5($this->_password) : $_SESSION['password'];
    $this->_remember = ($this->_login && $_POST['remember'] == "on")? 1 : 0;

    if(isset($_COOKIE["username"]))
        $_SESSION['username'] = $_COOKIE["username"];
    if(isset($_SESSION["password"])){
        $_SESSION['password'] = $_COOKIE["password"];   
    }


  }

  public function isLoggedIn()
  {
    ($this->_login)? $this->verifyPost() : $this->verifySession();

    return $this->_access;
  }
  public function filter($var)
  {
    return preg_replace('/[^a-zA-Z0-9]/','',$var);
  }

  public function verifyPost()
  {
    try
    {
        $excMsg = array();
      if(!$this->isTokenValid())
         $excMsg[] = 'Oops! We encountered a problem logging you in securely! Prehaps you are trying to log in from a different window? Please try again';
        if(!$this->doesUsernameExist()){
             $excMsg[] = 'The username field is required!';
          }
          if(!$this->doesPassExist()){
                $excMsg[] = 'The password field is required!';
          }
      if(!$this->isDataValid() && $this->doesUsernameExist() && $this->doesPassExist()){
          $excMsg[] = 'Only Alpha-Numeric characters are allowed! (A-Z, 1-9)';
      }

      if(!$this->verifyDatabase() && empty($excMsg))
        $excMsg[] = 'Invalid Username/Password';
        if(!empty($excMsg))
            throw new Exception(implode("<br>", $excMsg));


    $this->_access = 1;
    $this->registerSession();
    }
    catch(Exception $e)
    {
      $this->_errors[] = $e->getMessage();
    }
  }

  public function verifySession()
  {
    if($this->sessionExist() && $this->verifyDatabase())
       $this->_access = 1;
  }

  public function verifyDatabase()
  {
      require('inc.all.php');
      if($suspended){
            return false;  
      }
      $db = new MySQLi('localhost', 'root', '', 'minecraftprofiles');
      $sql = "SELECT ID FROM user_login WHERE username = '{$this->_username}' AND password = '{$this->_passmd5}'";
      $data = $db->query($sql);
    if($data->num_rows)
      {
        list($this->_id) = @array_values($data->fetch_assoc());
        return true;
      }
    else
      { return false; }
  }

  public function isDataValid()
  {
    return (preg_match('/^[a-zA-Z0-9]/',$this->_username) && preg_match('/^[a-zA-Z0-9]/',$this->_password))? 1 : 0;
  }
  public function doesUsernameExist(){
        return ($_POST['username'] == '')? 0:1;  
  }
  public function doesPassExist(){
        return ($_POST['password'] == '')? 0:1;
  }

  public function isTokenValid()
  {
    return (!isset($_SESSION['token']) || $this->_token != $_SESSION['token'])? 0 : 1;
  }

  public function registerSession()
  {

    $_SESSION['ID'] = $this->_id;
    $_SESSION['username'] = $this->_username;
    $_SESSION['password'] = $this->_passmd5;
    if($this->_remember){
        $expire=time()+60*60*24*180;
        setcookie("ID", $this->_id, $expire);
        setcookie("username", $this->_username, $expire);
        setcookie("password", $this->_passmd5, $expire);    
    }
  }

  public function sessionExist()
  {
    return (isset($_SESSION['username']) && isset($_SESSION['password']))? 1 : 0;
  }

  public function showErrors()
  {
    echo "<br><font color=\"#FF0000\">";
    foreach($this->_errors as $key=>$value)
      echo $value."<br>";
    echo "</font>";
  }

}
?>

The above is a login class that successfully saves and loads sessions (and cookies). I am doing my login code a different way so it is ajax compatible. My current login class:

<?php
require_once ("../../inc/inc.all.php");

if (isset($_POST['username'])) {
    $GLOBALS['username'] = $_POST['username'];
} else {
    echo "Username field is not set!";
    die();
}

if (isset($_POST['password'])) {
    $GLOBALS['passmd5'] = md5($_POST['password']);
} else {
    echo "Password field is not set!";
    die();
}

if (isset($_POST['remember'])) {
    $GLOBALS['remember'] = ($_POST['remember'] == "true")? 1 : 0;
}

if (!isset($_POST['token'])) {
    echo "There was a problem logging you in securly! Prehaps you are trying to log in from a different window?";
    die();
} else {
    $GLOBALS['token'] = $_POST['token'];
}

if (!validToken()) {
    echo "There was a problem logging you in securly! Prehaps you are trying to log in from a different window?";
    die();
}
if (isEmail()) {
    if (loginEmail()) {
        save();
    } else {
        echo "Unknown username/password!";
        die();
    }
} else {
    if (loginUsername()) {
        save();
    } else {
        echo "Unknown username/password!";
        die();
    }
}

function loginEmail() {
    $sql = "SELECT * FROM cs_users WHERE email = '{$GLOBALS['username']}' AND password = '{$GLOBALS['passmd5']}'";
    global $db;
    $query = $db -> query($sql);
    if ($query -> num_rows) {
        list($GLOBALS['id']) = @array_values($query -> fetch_assoc());
        $row = $query -> fetch_assoc();
        $GLOBALS['username'] = $row['username'];
        return true;
    } else {
        return false;
    }
}

function loginUsername() {
    $sql = "SELECT ID FROM cs_users WHERE username = '{$GLOBALS['username']}' AND password = '{$GLOBALS['passmd5']}'";
    global $db;
    $query = $db -> query($sql);
    if ($query -> num_rows) {
        list($GLOBALS['id']) = @array_values($query -> fetch_assoc());

        return true;
    } else {
        return false;
    }
}

function save() {
    if ($GLOBALS['remember']) {
        // User wants to be remembered, save cookies.
        $expire = time() + 60 * 60 * 24 * 180;
        setcookie("id", $GLOBALS['id'], $expire);
        setcookie("username", $GLOBALS['username'], $expire);
        setcookie("password", $GLOBALS['passmd5'], $expire);
    } else {
        $_SESSION['id'] = $GLOBALS['id'];
        $_SESSION['username'] = $GLOBALS['username'];
        $_SESSION['password'] = $GLOBALS['passmd5'];
    }
    echo true;
}

function isEmail() {
    if (filter_var($GLOBALS['username'], FILTER_VALIDATE_EMAIL)) {
        return true;
    } else {
        return false;
    }
}

function validToken() {
    return (!isset($GLOBALS['token']) || $GLOBALS['token'] != $_SESSION['token']) ? 0 : 1;
}
?>

I am validating the login information via this class:

<?php

class Login {

    private $_username;
    private $_password;

    private $_access;
    public $_status;

    public function __construct() {
        $this -> _access = 0;
        if (isset($_SESSION['username'])) {
            $this -> _username = $_SESSION['username'];
        }
        if (isset($_SESSION['password'])) {
            $this -> _password = $_SESSION['password'];
        }

        if (isset($_COOKIE['username'])) {
            $_SESSION['username'] = $_COOKIE['username'];
            $this -> _username = $_COOKIE['username'];
        }
        if (isset($_COOKIE['password'])) {
            $_SESSION['password'] = $_COOKIE['password'];
            $this -> _password = $_COOKIE['password'];
        }
    }

    public function isLoggedIn() {
        $this -> verifySession();
        return $this -> _access;
    }

    public function verifySession() {
        if ($this -> sessionExist() && $this -> verifyDatabase())
            $this -> _access = 1;
    }

    public function sessionExist() {
        return (isset($_SESSION['username']) && isset($_SESSION['password'])) ? 1 : 0;
    }

    public function verifyDatabase() {
        require_once (dirname(__FILE__) . "/../config.php");
        global $config;
        $DB_NAME = $config['db']['dbName'];
        $DB_HOST = $config['db']['host'];
        $DB_USER = $config['db']['username'];
        $DB_PASS = $config['db']['password'];
        $DB_PORT = $config['db']['port'];

        $db = new MySQLi($DB_HOST, $DB_USER, $DB_PASS, $DB_NAME, $DB_PORT);
        if (mysqli_connect_errno()) {
            printf("Connection failed: %s\n", mysqli_connect_error());
            return false;
        }
        $sql = "SELECT ID from cs_users WHERE username = '{$this->_username}' AND password = '{$this->_password}'";
        $data = $db -> query($sql);
        if ($data -> num_rows) {
            return true;
        } else {
            return false;
        }
        return false;
    }

    public function getUsername() {
        if (isset($_SESSION['username']))
            return $_SESSION['username'];
    }

    public function getStatus() {
        echo $this -> _status;
    }

    private function addStatusMsg($msg) {
        $this -> _status = $this -> _status + $msg + "<br>";
    }

}
?>

I think I narrowed down the issue to this part of the __construct method.

if (isset($_COOKIE['username'])) {
    $_SESSION['username'] = $_COOKIE['username'];
    $this -> _username = $_COOKIE['username'];
}
if (isset($_COOKIE['password'])) {
    $_SESSION['password'] = $_COOKIE['password'];
    $this -> _password = $_COOKIE['password'];
}

I am saving the cookies via

// User wants to be remembered, save cookies.
$expire = time() + 60 * 60 * 24 * 180;
setcookie("id", $GLOBALS['id'], $expire);
setcookie("username", $GLOBALS['username'], $expire);
setcookie("password", $GLOBALS['passmd5'], $expire);

What am i doing wrong?? Its been bugging me for hours

mrkirby153
  • 75
  • 2
  • 7
  • You should use [password_hash](http://www.php.net/password_hash) for password hashing. Unsalted `md5` is a very poor choice for password hashing. Not to mention your script is vulnerable to SQL injection and it is generally considered bad practice to use global variables. – Mike Jan 07 '14 at 00:34
  • And if you just do `$_SESSION['username'] = $_COOKIE['username']` without any sort of validation, I can just set a cookie and be logged in with any user I want. – Mike Jan 07 '14 at 00:37
  • Also, I highly recommend: http://stackoverflow.com/a/477578/811240 (see part II) – Mike Jan 07 '14 at 00:44
  • @Mike I know that my script is vulnerable to SQL injection and need to hash my passwords more securely. And that I need to validate cookies before setting it. My site is still HUGELY in development and should have some kinks. Also, how could I get around the ajax login without using global variables? – mrkirby153 Jan 07 '14 at 01:02
  • It really takes very little extra time to code securely, but trying to refactor old and insecure code months down the road when it is not fresh in your mind and you're just asking for disaster (believe me, I've been there). And I'm not sure what you mean by "getting around the ajax login". What you're looking for is [dependency injection](https://www.google.com/search?q=dependency+injection+php). – Mike Jan 07 '14 at 01:09

1 Answers1

0

Read the Common Pitfalls: at http://us2.php.net/setcookie . That should answer your question. $_COOKIEs are not available until the next loading of the page. You can probably send header("LOCATION:{$_SERVER['PHP_SELF']}");

StackSlave
  • 10,198
  • 2
  • 15
  • 30