I am reading a lot regarding the best practice to monitor when a user is logged in or not.
Currently i am trying to use a variable in a session like below:
login.php
<?php
session_start();
//I set that variable to false
$_SESSION['LOGGED_IN'] = FALSE;
{follows some code that checks the username and the password provided by the user
in an HTML form with POST request against the records of the database. If a match is
found then it allows the user to proceed with the loggin}
if($statement->rowCount() = 1) //
{
session_regenerate_id(true);
$_SESSION['LOGGED_IN'] = TRUE;
header('Location: mainpage.php');
}
else
{
echo "wrong username or password";
}
?>
mainpage.php
<?php
session_start();
if(($_SESSION['LOGGED_IN'] == TRUE) && isset($_SESSION['LOGGED_IN']))
{
echo "You are now logged in!";
}
else
{
echo "You are not logged in. Please retry.";
}
?>
The problem is that when i use a correct pair of credentials SOMETIMES i log in getting the "You are now logged in!" message, and sometimes using the same credentials i get the "You are not logged in. Please retry.".
I've added that message in the else statement on purpose. Normally there i will insert a redirection to the login page.
I am getting confused because this is an error that i shouldn't have. In the login.php script i am making sure that in order to redirect to the mainpage.php the $_SESSION['LOGGED_IN'] = TRUE. So that value should be transferred to the mainpage.php as TRUE and not FALSE.
What am i missing here?
And a general question regarding loggin:
Is it better to keep the login value (TRUE or FALSE) in a session or use a table in MySQL with a flag indicating when a user is logged in or not?
Thanks!
Related
I've tried to be as specific as possible, but I'm sorry that the subject of my question may be broad.
I got used to a habit of sending variables using the $_GET['variable'], for instance, let's say I'm using ajax to get some information from a database, I would probably do something like this:
xmlhttp.open("GET","read.php?option=someoption",true);
And then I would set the PHP page in a way that behave differently according to the $_GET['option'] it would receive.
I then realised that any logged-in user could type the URL and directly modify the database, so I've set some additional $_SESSION['redirect'] variables before each redirection to help prevent access to php pages from URL. By doing a quick ajax call to a "prevent.php" page that would do something like so:
$_SESSION['redirect'] = "true";
header("Location: page.php");
And then having it set this way in the page.php for instance:
if ($_SESSION['redirect']==true) {
// access the database
}
else {
// deny access
}
Is this a reliable way of doing things, or is there a more professional way to sort it out?
No it's not a secure way of doing it.
Here's an example of how you could achieve a secure user system in the simplest of forms:
login.php
<?php
session_start();
$user = isset($_POST['username']) ? $_POST['username'] : false;
$pass = isset($_POST['password']) ? $_POST['password'] : false;
# Check credentials
if (validCredentials($user, $pass)) {
# Credentials are valid
# Set isAdmin session for the user 'admin'
# This is hardcoded for simplicity but
# you could read a value from a database
# and set this session dynamically.
if ($user === 'admin') {
$_SESSION['isAdmin'] = true;
}
# Generate CSRF token (see appendix)
# heads up: random_bytes() is a PHP7 function.
$_SESSION['token'] = bin2hex(random_bytes(32));
# Set logged in session for every user
$_SESSION['user'] = $user;
echo 'Successfully logged in!<br />';
echo 'Go to the user page.';
}
admin-page.php:
<?php
session_start();
if (isset($_SESSION['isAdmin']) && $_SESSION['isAdmin'] === true) {
echo 'Only the admin can see this.';
} else {
echo 'You are either not logged in or you don\'t have the permission to view this page.';
}
user-page.php:
<?php
session_start();
if (isset($_SESSION['user'])) {
$token = $_SESSION['token'];
echo 'Only logged in users can see this. <br />';
echo 'Log me out.';
} else {
echo 'You are not logged in.';
}
Appendix:
Make sure that you protect yourself against CSRF attacks:
For example an insecure way of logging an user out would be:
logout.php:
<?php
session_start();
if (isset($_SESSION['user'])) {
session_destroy();
}
Maybe you ask yourself why this is not secure.
The reason is because for every user the logout link is the same (example.com/logout.php).
So it's not hard at all to guess the logout link (well, we don't even have to guess, we already know for sure).
An attacker could disguise the logout link and as soon as you click on it you would be logged out.
It's very important to understand that the logout is just one example.
Think of a more severe action like deleting a user etc.
So this concept applies to every action an authenticated user can do.
To be safe, you can generate a token as soon as the user has logged in.
For every action taken you then check if the token in the request matches the one you generated.
This way the logout link is unique for every user (example.com/loogut.php?token=random_token_generated_at_login) and is only hardly guessable by an attacker.
safe-logout.php:
<?php
session_start();
if (isset($_SESSION['user'])) {
# Check if the user specified token matches ours
$token = isset($_GET['token']) ? $_GET['token'] : false;
if ($_SESSION['token'] === $token) {
session_destroy();
echo 'Successfully logged out!';
} else {
# We dont logout because the token was not valid
}
}
And NO: a POST request is just as susceptible as a GET request.
So make sure you check the token for every action, regardless of the HTTP method used.
I want this: If the user logs out(session destroy) then index should say: You are logged out.
if (isset($_SESSION['user']) && $_SESSION['user'] == true) {
echo "Welcome on the users page!, " . $_SESSION['username'] . "!";
}
elseif (!isset($_SESSION['user'])) {
echo "You logged out..";}
The problem I am having is that it also shows you logged out when you haven't even logged in to be able to log out. I only want it to show if the user logs out.
Also I only want "You are logged out" to show up once. If you refresh the page, it should be gone
Instead of using php unset(); function to destroy a session, you can actually save boolean "false" in the $_SESSION["user"];
For example, in you logout page:
Instead of destroying, set session to false
Ex:
``
//When logging out
$_SESSION["user"] = false;
//now to check if user logged out
if($_SESSION["user"] === false) {
echo "you logged out";
}elseif(!isset($_SESSION["user"])) {//when the session finally expires
echo " you haven't logged in";
}else{
echo "you are logged in";
}
//to get rid of it after page reload, you need to unset the SESSION
unset($_SESSION["user"]);
That is because of the following condition:
!isset($_SESSION['user']
This is true whether the user logged-in or not. So you have to make some other session variable to check for the user logged out. And that is only set when the user logged out.
Ex:
if( !isset($_SESSION['user'] && isset($_SESSION['logged_out']))
{
// isset($_SESSION['user'] to check if user logged out and extra condition to check if user comes here after logged-out.
}
and check this on index page.
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;
}
?>
first off all my English is not very good. Sorry I do my best. I am developing a CMS system. I need an inlog system for it. If you are not logged in you can't view some of the pages. I created a php session of it but it doesn't work on the other pages... I will include some off the code I wrote.
On the page I check the username and password, I created the session like this. And worked with session to check username and password, so it works on that page.
<?php
session_start();
$_SESSSION['gebruikersnaam'] = $_POST['gebruikersnaam'];
$_SESSSION['wachtwoord'] = $_POST['wachtwoord'];
if(($_SESSSION['gebruikersnaam'] == 'admin')
&& ($_SESSSION['wachtwoord'] == 'admin123')) {
include("adminpanel.php");
} else {
echo "Uw gebruikersnaam of wachtwoord is foutief.";
}
?>
On my other pages I added this to check if the user is logged in. I seem to never get that I am logged in and I can't echo the session out. Here is the code!
if(!empty($_SESSION['gebruikersnaam']['wachtwoord'])) {
echo "not ingelogd";
}
If the conditional statement with the session works, I can redirect the user to the log in page if he is not logged in.
Thanks in advance you would help me a lot!
That's because of a slip of the tongue, its $_SESSION not $_SESSSION and also:
$_SESSION['gebruikersnaam']['wachtwoord'];
Is actually referring to 1 value, not two:
$data = array('gebruikersnaam' => array('wachtwoord' => 'mijnwachtwoord'));
echo $data['gebruikersnaam']['wachtwoord'];
Instead do:
if(!empty($_SESSION['gebruikersnaam']) || !empty($_SESSION['wachtwoord'])){
echo "not ingelogd";
}
However, you should only store a username and id in a session. Storing the password is a potential security breach and is not necessary.
You could also use something like this to scan for required values:
function required_session_fields(array $keys){
foreach($keys as $k){
if(!array_key_exists($k, $_SESSION) && empty($_SESSION[$k])){
return false;
}
}
return true;
}
if(required_session_fields(['gebruikersnaam', 'wachtwoord'])){
echo 'gelukt';
}
If you started the session and included a file, you can still access the $_SESSION variable. On every new server request, make sure the session is started.
On the other pages you must have
session_start();
before
if(!empty($_SESSION['gebruikersnaam']['wachtwoord'])) {
echo "not ingelogd";
}
However this variable $_SESSION['gebruikersnaam']['wachtwoord'] is never created. Currently you have created $_SESSION['gebruikersnaam'] and $_SESSION['wachtwoord']
Perhaps you meant to have something like
if(!empty($_SESSION['gebruikersnaam']) && !empty($_SESSION['wachtwoord'])) {
echo "not ingelogd";
}
$loggedin = false;
if ($_SESSION) { //user loggedin
$loggedin = true;
...//get token
}
...
if($loggedin){
echo 'Hi '.$user['name'];
}
else{
echo 'Please log in';
}
...
I suppose the web page will display "please log in" when I log out. But it says "undefined $user variable at /src/myproject/index line 80". And after I refresh the page, it says "please log in".
What is the problem here? Thank you for your help.
From what I can tell from your pseudo code, you have some sort of key in the $_SESSION variable that says the user is logged in.
For demonstration, let's assume you do something like... After the user logs in, you assign $_SESSION['user'] = an array of user information. One of those keys is 'name'.
So, your code should look something like this
$loggedin = false;
if (isset($_SESSION['user'])) {
$loggedin = true;
}
if ($loggedin) {
echo "Hi " . $_SESSION['user']['name'];
}
else {
echo "You are not logged in."
}
Please keep in mind this is just a solution for your code sample you posted. To do this properly, I would suggest the following changes:
create a class that handles authentication
create methods in that class to determine if the user is logged in or not
create methods to return the current logged in user.
This will make your code more extensible, reuseable and easier to follow in the future.
Best of luck.