0

I would like to be sure that a $_SESSION cannot be fooled in a login scheme involving it. I over-simplified it here to keep only the core of the question.

When using

<?php 
$password = "...";

session_set_cookie_params(3600, dirname($_SERVER['SCRIPT_NAME']));
session_start();

if (isset($_POST['pass']) && $_POST['pass'] === $password) { 
    $_SESSION['iamlogged'] = 1; 
}

if (!isset($_SESSION['iamlogged']) || !($_SESSION['iamlogged'] == 1)) { 
    echo '<html><body><form action="." method="post"><input type="password" name="pass" '
         . 'value=""><input type="submit" value="Submit"></form></body></html>'; 
    exit; 
}

echo "You logged in in the last 30 minutes.";
// Now we can do some work

is it sure that the last line cannot be displayed for anyone not having the password? Or is there a currently known technique in PHP, to manually force this $_SESSION['iamlogged'] value?

Note: Of course, I do use password hasing+salting, etc., but I removed all of this to focus only on the $_SESSION safetyness.

Note2: I assume register_globals is off because PHP is newer than 5.4.

Note3: Here is a live version.

Basj
  • 41,386
  • 99
  • 383
  • 673
  • I must've read this 10 times and I'm not grasping. What do you mean by "fooled"? As in "hacked/spoofed/bypassed/middle man"? And this `echo "Can we arrive here without the password?";`, was that part of the question? – Funk Forty Niner Nov 17 '17 at 23:40
  • @Fred-ii- I mean, except brute forcing all passwords, except man in the middle, is it possible for a user not knowing the password to get this last line (`echo ...`) displayed? Example: can you get this line displayed in http://secret-ravine-92114.herokuapp.com/ ? – Basj Nov 17 '17 at 23:43
  • the echo will always appear, regardless. You'd need to place it inside the condtional statement of a user already logged in and the session is set. – Funk Forty Niner Nov 17 '17 at 23:44
  • @Fred-ii- no it won't: if you're not logged, it will stop in the previous `exit;` and the last line won't be executed. – Basj Nov 17 '17 at 23:44
  • yeah you're right, my bad; I stand corrected. @Basj – Funk Forty Niner Nov 17 '17 at 23:47
  • 2
    Session data is stored on the server, it can't be set by the client. The only way to fool sessions is for someone to guess someone else's `PHPSESSID` cookie. – Barmar Nov 17 '17 at 23:47
  • @Barmar this candidate-duplicate is rather vague (no code at all), it's very difficult to understand what it exactly deals about (except if you already know the answer). – Basj Nov 17 '17 at 23:58
  • @Basj I think it answers the basic question that session variables are pretty safe from tampering. – Barmar Nov 18 '17 at 00:03

1 Answers1

0

The session may possibly give you a false positive if there is a relic $_SESSION['iamlogged'] floating around from previously.

As a safety measure, you should do:

<?php 
$password = "...";

//unset false positive, if it exists
if (array_key_exists('iamlogged', $_SESSION)) {
    unset($_SESSION['iamlogged'];
}

//carry on normally
if (isset($_POST['pass']) && $_POST['pass'] === $password) { 
    $_SESSION['iamlogged'] = 1; 
}
...

Or you could do it this way for simplicity:

session_start();
session_destroy();
session_start();

However the latter here would also lose everything else in $_SESSION, so if there's other relevant stuff in there you want to retain, don't do it the second way.

mopsyd
  • 1,877
  • 3
  • 20
  • 30
  • Thanks for your answer. Just to be sure to understand @mopsyd, why do you start, destroy and start? (I updated question to show that, if logged, I would like to stay logged for 30 minutes. There is, in my app, other code to log out (+ other code to use hash+salt), but I didn't post it here.) – Basj Nov 17 '17 at 23:49
  • `session_destroy` can't destroy a non-existent session, and if you haven't called `session_start`, it doesn't exist yet for the current runtime. – mopsyd Nov 17 '17 at 23:50
  • Wouldn't this destroy an existing cookie? (Let's say I want to stay logged in for 30 minutes, once logged.) – Basj Nov 17 '17 at 23:51
  • First `session_start` makes PHP aware that there is a session, then `session_destroy` kills it, then `session_start` creates a fresh one. – mopsyd Nov 17 '17 at 23:51
  • The hash value of the cookie corresponds to the name of a temp file in PHP's session directory, which is a flatfile of the session values. If `session_start` has not been called, then `PHPSESSID` is just a cookie and has no relevance. You can probably unset the cookie also, but since `PHPSESSID` can be renamed, PHP does not make any assumptions about what it means until it is bound to a currently active session. – mopsyd Nov 17 '17 at 23:53
  • For funsies, you can change the name of the actual cookie from `PHPSESSID` to whatever else you want with `session_name('newSessionCookieName');`. You will need to call that again on each subsequent page load with the same name to retain it also though. If you want to get super complicated, you can juggle multiple sessions for the same user by doing this, but that is really not recommended. It could be useful in some cases though, like if you need a superadmin to be able to temporarily spoof a lower level user account without having to log back in as the superuser again when they logout. – mopsyd Nov 17 '17 at 23:56
  • If your login state is determined by the presence of `$_SESSION['iamlogged']` and it must evaluate to `true`, then the presence of a `$_SESSION` would not make you logged in unless it had `iamlogged=1`. `$_SESSION` itself is just a statefully persistent array, and doesn't mean anything unless your logic tells it to. – mopsyd Nov 18 '17 at 00:08
  • I understand your code is valid if it's for auth / login page, i.e. the password is passed anyway at each request. (If on the other hand the php file needs to do other things like editing, posting content, then we should keep session and not unlink it) – Basj Nov 18 '17 at 00:33
  • That is correct. – mopsyd Nov 18 '17 at 00:35