I've got a small problem with my smarty project, logout problem to be precise. I have a index.php page which is the "main" page and it gets POST data and directs actions based on current data. There`s checking if the session variables has been set. Now when I login I have function like this:
function login($value)
{
$res = $this->sql->checkLogin($value);
if($res)
{
//checks if user is admin
$isadm = $this->sql->isAdm($value);
if($isadm == true)
{
$_SESSION['user'] = $value['name'];
$_SESSION['adm'] = true;
$message = 'Admin';
$this->tpl->assign('var', $message);
if($_SESSION['adm'] == true)
{
//sets some variables for admin users
$navigation = 'navi';
$this->tpl->assign('navigation', $navigation);
}
$this->tpl->display('maint_main.tpl');
}
//user is not admin
else
{
$_SESSION['user'] = $value['name'];
$_SESSION['adm'] = false;
$message = 'Perus';
$this->tpl->assign('var', $message);
if($_SESSION['adm'] == true)
{
$navigation = 'navi';
$this->tpl->assign('navigation', $navigation);
}
$this->tpl->display('maint_main.tpl');
}
}
//login failes, show login form and info
else
{
$message = 'Login failed';
$this->tpl->assign('var', $message);
$this->tpl->display('login_form.tpl');
}
}
and logout function :
function logout()
{
setcookie(session_name(), '', time()-42000, '/');
session_unset();
session_destroy();
$this->tpl->display('login_form.tpl');
}
These work just about the way they are supposed to but the real problem occurs when I log out and redirect to the login_form.tpl. If I use the back button of the browser the POST data with username and password is retrieved and the login goes through again. This causes that those pages behind login are still viewable. As I am not quite familiar with Smarty yet I couldn`t figure out any way to fix this. So basically how to prevent access to that POST data after logout?
I don't think this has anything to do with smarty. This is a browser/http generic issue. Most browsers will re-post form data after confirmation from the user.
One approach to make re-posts of the form invalid would be to pass along a secret code/token (perhaps a guid or your session id) which is also stored in session data. When the user logs out, clear their session (or at least the secret code you're checking). When the user logs in, check to make sure that the confirmation code matches the one for the current session.
This pattern is often used to manage csrf attacks and is often known as a 'synchronizer token'. This blog post provides a good explanation https://blog.whitehatsec.com/tag/synchronizer-token/
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 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;
}
?>
This question already has answers here:
PHP ending sessions(different ways) i dont understand
(2 answers)
Closed 9 years ago.
I have a PHP login and log out script and what I'm trying to achieve is that when the user click on the log out link he completely logs out, regardless clicking the back button of the browser, and do not want the user to access the page.they should be redirected to the login page
this is login function
function loggedin() {
if ( isset($_SESSION['user_id']) && !empty($_SESSION['user_id']) ) {
return true;
} else{
return false;
}
}
and this is my logout script
<?php
include 'includes/connect.php';
include 'includes/functions.php';
session_destroy();
header('location: index.php');
?>
how can i achieve this??
You can delete all cookies
if (isset($_SERVER['HTTP_COOKIE'])) {
$cookies = explode(';', $_SERVER['HTTP_COOKIE']);
foreach($cookies as $cookie) {
$parts = explode('=', $cookie);
$name = trim($parts[0]);
setcookie($name, '', time()-1000);
setcookie($name, '', time()-1000, '/');
}
}
http://www.php.net/manual/en/function.setcookie.php#73484
And if you have an array of cookie names used for login authentication, you should iterate the cycle only with them.
The question was logging out a user completely from a website and not just how do I destroy a PHP session, so my answer will be somewhat more complex.
Since you're using PHP's $_SESSION functionality to handle the user sessions, you can, in particular, tie the current session IDs to the user accounts. Then you can easily force the session to expire.
For example, create a new field in the user database, and call it active_session_id or something. Every time a user logs in, save the session_id() output to it. Then inside of your loggedin() function check if the session_id() of the current request matches the one saved when the user was logging in, and if it does not match, the function will return false, so this is how you virtually end a user session. I.e. even though it will still actually be there, it will not be valid anymore.
It is worth noting that the solution above would be sort of a one-to-one relation, i.e. one user will be able to have only one active session. If you want to allow users to come from different places at the same time, you'll have to maintain a one-to-many relation there by creating a new table called e.g. users_sessions and saving the session IDs there. Please do not create another fields in the current users table like active_session_id_1, active_session_id_2 etc. because it is not considered to be a good practice.
Hope this helps
You can write a generic function that checks if a user is logged in, if not just redirect them like this
function isLoggedIn(){
if (isset($_SESSION['user_id']) && !empty($_SESSION['user_id'])){
//do what you want
} else{
header("location:youloginpage.php");
}
}
If you do not specify more on your question, we can only procede by assumptions. Anyway, since you are using that SESSION, and it's not clear if you want to destroy the data contained or not, the function to check if user is logged in, could be modified this way:
function loggedin() {
if ( isset($_SESSION['user_id']) && is_numeric($_SESSION['user_id']) && ($_SESSION['user_id'] > 0) ) {
return true; //user is logged in
//other operations to be performed
} else{
return false; //user is NOT logged in
//other operations to be performed
}
}
The logout function could just be something like this:
function logout() {
if ( isset($_SESSION['user_id']) && is_numeric($_SESSION['user_id']) && ($_SESSION['user_id'] > 0) ) {
$_SESSION['user_id'] = -1; //"unsets" the user, while not destroyng session
} else{
return false; //user is already logged out - do nothing
}
}
A php newbie here.
Below is the code I'm using to build a login system to enter mypage.php
It's working great but it is quite naive, anyone can type mypage.php in the url and avoid the login page.
How can I build it more secure?
Thanks a lot!
if(isset($_POST['submit'])) {
$user = $_REQUEST['user'];
$pass = $_REQUEST['pass'];
$sql = "SELECT * FROM login WHERE user='".$user."'";
$res = $this->new_db->select($sql);
$row = $this->new_db->get_row($res);
if (isset($row)) { //user exists?
if($row["pass"] == $pass){
$_SESSION['userId'] = $row['user'];// TRYING WITH SESSIONS
header("Location: mypage.php");
} else {
echo "wrong pass";
}
} else {
echo "user does not exist";
}
}
Then in mypage.php
if(isset($_SESSION['userId'])) {
//contents
} else {
echo "there's an error";
}
It is printing "there's an error"
why??
Thanks a lot
Three things:
Don't store passwords in plain text. Given this code, I can only assume that's what you're doing. You should store the passwords hashed, hash the password the user enters, and compare those.
You have a SQL injection vulnerability. Any time you're receiving input from the user that's destined for a database query, at the very least you should wrap it in mysql_real_escape_string().
On the logged-in page (on any logged-in page) you'll want to track whether or not the user is logged in. One simple way to do this is to have the login form set a $_SESSION value indicating the user's current logged-in status. Then on any page which requires a user to be logged in, check for that value. If it exists, they've previously logged in. If it doesn't, they haven't. It's simple, but good enough to get your going for what you need.
yes, there might be sql-injection in your code
in order to prevent you may use mysql_real_escape_string function
Check my answer here i posted before some time, which explains how you should go with login systems.
Open-source rich HTML editor
You will need to put something in mypage.php to check to see if the user is "logged in". I have done this in the past with the Zend Auth module from the Zend Framework. The cool thing about it is it can be used alone, (you don't have to make a whole Zend Framework site to use the Auth module). I used the Zend Auth Page to figure out how to use it.
Then, once I setup the auth session using the Zend Session, I just checked at any other page to see if the user was "logged in" with something like this:
private function _loggedIn()
{
$loggedIn = false;
$Namespace = new Zend_Session_Namespace('Zend_Auth');
foreach ($Namespace as $index => $value) {
$loggedIn = ($value->user_id);
}
return $loggedIn;
}
First of all, you have to protect your mysql query from sql injection. This can be achieved by adding mysql_real_escape_string like that:
$user = mysql_real_escape_string($_REQUEST['user']);
Then, if you don't want users to be able to visit mypage.php without being logged in, you should set some cookie in your login script if the login is successful, and then, on mypage.php, check that cookie to see if it matches in your database. Something like that:
login.php:
if($row["pass"] == $pass){
setcookie("userid",$user);
setcookie("passhash",sha1($pass));
...
mypage.php
$res = mysql_query("select * from login where user='".mysql_real_escape_string($_COOKIE['userid'])."' limit 1");
$row = mysql_fetch_assoc($res);
if($_COOKIE['passhash'] == sha1($row['pass']))
{
die("logged in OK");
}
else
{
die("please log in");
}
if (isset($_POST['submit'])) {
$user = $_REQUEST['user'];
$pass = $_REQUEST['pass'];
$sql = "SELECT user FROM login WHERE user='".mysql_real_escape_string($user)."' AND pass=SHA1('".mysql_real_escape_string($pass)."')";
$res = $this->new_db->select($sql);
$row = $this->new_db->get_row($res);
if ($row['user'] != "") { //user exists?
header("Location: mypage.php");
}else{
echo "username and password combination is wrong";
}
}
Ok, having trouble here:
I created a login script, so after a person logs in then they will get direted to another page. And also, I have it redirecting them to the login page if they try and access one of those other pages.
My problem is, if a user is logged in and stumbles to the login page again --by accident-- I would like for it to recognize that the user is logged in and redirect them to that next page (which is index2.php) ?? Having troubles :-(
Here is my code so far:
require_once "inc/functions.class.php";
$quickprotect = new functions('inc/ini.php');
if (isset($_SESSION['goAfterLogin'])){
$goto = $_SESSION['goAfterLogin'];
unset($_SESSION['goAfterLogin']);
}
else $goto = $quickprotect->settings['DEFAULT_LOGIN_SUCCESS_PAGE'];
if (isset($_POST[username])) {
if($quickprotect->login($_POST[username], $_POST[password])) header ("Location: $goto");
}
Here is how I store a users session in the functions page
public function is_logged_in() {
//Determines if a user is logged in or not. Returns true or false;
if ($_SESSION['logged_in'] === md5($this->settings[ADMIN_PW])) {
return true;
}
else return false;
}
You don't mention how you store your users in your session, but something like this should do it for you:
if(isset($_SESSION['user']))
{
header("Location: index2.php");
exit;
}
This will check if you have a user in your session, and if so, redirect to index2.php.
You need to change 'user' according to your session key.