0

Here is some php+mysql.

<?php
require('Cookie.php');
require('User.php');
require('DbConnection.php');

$user = new User($_POST['login'], $_POST['pass']);

$dbConn = new DbConnection();
$conn = $dbConn->getConnection();

$isExistUser = "SELECT * FROM users WHERE login = '$user->login' and pass = '$user->pass'";
$result = mysqli_query($conn, $isExistUser) or die(mysqli_error($conn));
$count = mysqli_num_rows($result);

//$cookie = $result->fetch_assoc()['sessid'];

if($count !== 1 ){
    echo json_encode(array('islogin' => false));
}else{
    //setcookie('SID', $cookie , time() + (60*60*24*365), '/', 'hostenko.net', null, true);
    echo json_encode(mysqli_fetch_object($result));
}

$dbConn->closeConnection();

?>

When I use this, I get data from db on the front side, but when I uncomment:

//$cookie = $result->fetch_assoc()['sessid'];

and try to set cookie,

//setcookie('SID', $cookie , time() + (60*60*24*365), '/', 'hostenko.net', null, true);

-it returns null.

What's the problem??

Momoro
  • 599
  • 4
  • 23
  • 1
    Where do you get null? When/how are you checking that value? – John Conde May 07 '20 at 17:09
  • I get null at this string --> echo json_encode(mysqli_fetch_object($result)); This is front side: login.addEventListener("click", async (e) => { const response = await serverRequest('server/login.php', {method: post, body: new FormData(form)}); console.log(response); }); response -> JSON from server – Андрей May 07 '20 at 17:20
  • That suggests your query didn't match any rows. Do you have correct values for `login` and `pass`? On that, you should really have the query retrieve the user based on username only, and then use `password_verify()` to match the password. Obviously you need to use `password_hash()` to store the password in the first place. – droopsnoot May 07 '20 at 17:29
  • There _are_ easier ways of settings _cookies_, like `localStorage` – Momoro May 07 '20 at 17:36
  • droopsnoot, the values are correct, i got it, when the logic with cookie are in comment. When i uncomment it - its a null. – Андрей May 07 '20 at 17:49
  • Momoro, is it correct way to store cookie at local storage? – Андрей May 07 '20 at 17:50
  • Please include what is in your Cookie.php file. Can't tell if you're starting the session properly, or what's going on in there. – Adam Winter May 07 '20 at 17:53
  • I posted an answer with `localStorage` – Momoro May 07 '20 at 17:58

2 Answers2

1

First off, most imporantly, at login you should be generating a new session ID, not reusing one that is stored in your database. The point where the user logs in should be used to start all session properties fresh. As droopsnoot said, you should be storing a hash of the password, not the password itself, this is a fundamental basic security procedure, not people's esoteric opinions.

<?php 
//require('Cookie.php');  //Not sure what's in here
require('User.php');  //Add to this class a hash of the password  $user->pwhash
//require('DbConnection.php'); //Can't tell what's in here

session_destroy();
ini_set('session.cookie_lifetime', 0);   //Pick your time here
ini_set('session.use_cookies', 1);
ini_set('session.use_only_cookies', 1);
ini_set('session.use_strict_mode', 1);
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_secure', 1);
ini_set('session.cookie_samesite', 'Strict');
ini_set('session.use_trans_sid', 0);
ini_set('session.hash_function', 'sha512');
ini_set('session.sid_length', '64');          //Use the generated sid
session_start();

$forhash=random_bytes(256);                    //I prefer to create my own
$hash = openssl_digest($forhash, "sha256");
$sid = base64_encode($hash);
$sid = substr($sid, 10, 64);
$_SESSION['sessionID']=$sid;

$obj = new stdClass();
    $obj->dateread = date("D M j G:i:s T Y");
    $obj->message = '';
    $obj->error = '';

if(!($login=@$_POST["login"])){
    echo '<p>No login was entered.</p>';
    exit;
}else {
    $login=$_POST["login"];
}

if(!($pass=@$_POST["pass"])){
    echo '<p>No pass was entered.</p>';
    exit;
}else {
    $pass=$_POST["pass"];
}

$user = new User($login, $pass);  //do not store the password in this object, only store the hash

$db = new mysqli('localhost', $dbuser, $userpw, $database);
if (mysqli_connect_errno()) {
        echo 'Error: Could not connect to database.';
        $obj->error = $obj->error.'Could not connect to database.  '.__FILE__.__LINE__;
        error_log(json_encode($obj));
        exit;
    }else{
        $obj->message = $obj->message.'Successfully connected to database.  ';
    }

$query = "UPDATE users SET sessid = ? WHERE login = ? AND pwhash = ?";
$stmt = $db->prepare($query);
$stmt->bind_param('sss', $sid, $login, $user->pwhash);
$stmt->execute();
if($db->affected_rows == 1){    
        echo echo json_encode(array('islogin' => true));  //or whatever else you might do here
    }else{
        echo json_encode(array('islogin' => false));
        exit;
    }

$db->close();

?>

Then, on subsequent other pages, while the user is logged in:

<?php
session_start();       
if(!isset($_SESSION['sessionID'])) 
    { 
        echo 'You are not logged in.  Please <a href="https://yousite.com/logout.php">click here</a>.';
        exit;
    }else{
        $sid = $_SESSION['sessionID'];
    }

require('User.php');
//require('DbConnection.php'); //Still don't know what's here

$user = new User;

$obj = new stdClass();
    $obj->dateread = date("D M j G:i:s T Y");
    $obj->message = '';
    $obj->error = '';

$db = new mysqli('localhost', $dbuser, $userpw, $database);
if (mysqli_connect_errno()) {
        echo 'Error: Could not connect to database.';
        $obj->error = $obj->error.'Could not connect to database.  '.__FILE__.__LINE__;
        error_log(json_encode($obj));
        exit;
    }else{
        $obj->message = $obj->message.'Successfully connected to database.  ';
    }


$query = "SELECT email, phone, whatever FROM users WHERE sessid = ?";
 $stmt = $db->prepare($query);
 $stmt->bind_param('s', $sid);
 $stmt->execute();
 $stmt->store_result();
 $stmt->bind_result($email, $phone, $whatever);
 if (mysqli_connect_errno()) {$obj->error = 'Error: Could not connect to database.  ';
                             echo json_encode($obj);
                             error_log(json_encode($obj));
                             exit;
 }
 else{
     if($stmt->num_rows == 1) {
          echo json_encode(array('islogin' => true));  //or whatever else you might do beside this
          while($stmt->fetch()){
             $user->setEmail($email);
             $user->setPhone($phone);
             $user->setWhatever($whatever); 
          }
     } elseif($stmt->num_rows == 0) {
          $obj->message=$obj->message.'Session not found.  ';
          echo json_encode(array('islogin' => false));
     } else {
         $obj->error = 'Database Error: Sessions not 1 or 0.  ';
         echo json_encode($obj);
         error_log(json_encode($obj));
         exit;
    }
}

$db->close();
?>
Adam Winter
  • 1,680
  • 1
  • 12
  • 26
  • I agree with these comments and, personally, use prepared statments and do not use die(). I just didn't want to get too far away from the original code, and make it too confusing, since there was a more fundamental issue I wanted to focus on. – Adam Winter May 07 '20 at 20:59
  • I like that you want to contribute to this site and you want to help, but when answering you should not copy OPs code as is. You should try to fix all problems even the ones which OP didn't ask about. The answer is not only for that one person, but it is supposed to teach everyone else how to code properly. – Dharman May 07 '20 at 20:59
  • @Dharman. OK, if that's the way it should be, I'll clean it up. – Adam Winter May 07 '20 at 21:00
  • Why are you checking for connection errors? `if (mysqli_connect_errno())` seems completely unnecessary. – Dharman May 07 '20 at 21:57
  • For thouroughness, I guess, that's the way I was taught. Assuming you have that part wrapped back up into a connection class, then you wouldn't be looking at that part of the code all the time. What's it going to hurt? Maybe it is completely unnecessary, until it's not. – Adam Winter May 07 '20 at 22:03
  • Please read: [Should we ever check for mysqli_connect() errors manually?](https://stackoverflow.com/q/58808332/1839439) – Dharman May 07 '20 at 22:04
  • Having read that now, I would just note that there is a difference between displaying and logging the errors. My personal thought on this is that displaying certain errors can give you a clue about what you're looking for when the user might report back to you the error they received. Naturally, you have to be careful about what you display to them. Also, I use some custom error logging, but I took that part out of this. – Adam Winter May 07 '20 at 22:15
-1

An easy alternative to "cookies" is localStorage


While it is not the "prettiest" method, it works.

localStorage.setItem('cookieconsent', true);

You can remove an item like so:

localStorage.removeItem('cookieconsent');

And you can also get the value of an item.

localStorage.getItem('cookieconsent');
Momoro
  • 599
  • 4
  • 23