Greetings,
I am working on a login system and getting stuck with Blackberry browsers authenticating. It seems they have an issue with PHP's session_regenerate_id(), can someone suggest an alternative? Here are the auth and login scripts:
UPDATE
It would appear that sessions in general are not working. Took out session_regenerate_id() just to see if it would work and it just redirects me every time, as though the $_SESSION['MD_SESS_ID']were blank. Really stuck here, any ideas would be appreciated. Cookies on the device are enabled, using a Blackberry Bold 9650. It works on my iPod Touch and every browser on my PC.
Login
<?php
session_start();
include $_SERVER['DOCUMENT_ROOT'] . '/includes/pdo_conn.inc.php';
//Function to sanitize values received from the form. Prevents SQL injection
function clean($str) {
$str = #trim($str);
if(get_magic_quotes_gpc()) {
$str = stripslashes($str);
}
return $str;
}
$username = clean($_POST['username']);
$password = clean($_POST['password']);
if ($username != "" && $password != "") {
$getUser = $db->prepare("SELECT id, username, password, salt FROM uc_dev WHERE username = ? LIMIT 1");
$getUser->execute(array($username));
$userDetails = $getUser->fetch();
$dbPW = $userDetails['password'];
$dbSalt = $userDetails['salt'];
$hashedPassword = hash('sha512', $dbSalt . $password);
if ($hashedPassword == $dbPW) {
//Login Successful
session_regenerate_id();
$_SESSION['MD_SESS_ID'] = $userDetails['id'];
header('Location: http://somewhere.com');
session_write_close();
} else {
header('Location: http://www.somewhere.com');
exit();
}
} else {
header('Location: http://somewhere.com');
exit();
}
?>
Auth
<?php
//Start the session
session_start();
//Verify that MEMBER ID session is present
if(!isset($_SESSION['MD_SESS_ID']) || (trim($_SESSION['MD_SESS_ID']) == '')) {
$_SESSION = array();
// Note: This will destroy the session, and not just the session data!
if (ini_get("session.use_cookies")) {
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000,
$params["path"], $params["domain"],
$params["secure"], $params["httponly"]
);
}
// Finally, destroy the session.
session_destroy();
header("Location: http://somewhere.com");
exit();
}
?>
A while ago, I was doing some Blackberry development, and found out that the browser couldn't handle multiple cookies with the same name. Not sure if they've fixed this yet.
So if you're sending out the Set-Cookie header more than once (using setcookie, session_start, or session_regenerate_id), using the same name each time, this could be causing your problem.
You might want to keep track of the cookies you need to output, in an object or array, and only send them to the browser at the very end of the request. This way, if you need to change their values in the middle of the request, you can just overwrite the array's value, rather than sending out another cookie header.
This page may also help -- someone linked to it from PHP's session_regenerate_id page.
Related
I have a working Session management on my platform which I programmed in PHP.
For security reasons I want to regenerate the Session ID at least when a user logs in successfully and if possible with each request to prevent session fixation.
The login part looks like this if the login credentials are correct. If they are not correct or the user has not entered anything yet I do not start a session and as far as I know one old value for the session id is used
session_set_cookie_params(1800, "/", $domain, true, true);
session_start();
session_regenerate_id(true);
Each time I make another request to the server and it checks wether my session is valid I call
session_regenerate_id(true);
I check for a valid session with this code:
$domain = $_SERVER["HTTP_HOST"];
if(session_status() != PHP_SESSION_ACTIVE)
{
session_set_cookie_params(0, "/", $domain, true, true);
session_start();
}
//Check if session has expired
$now = time();
if(isset($_SESSION["discard_after"]) && $now > $_SESSION["discard_after"])
{
session_unset();
session_destroy();
header("Location: https://".$domain."/login.php");
die();
}
session_regenerate_id(true);
$_SESSION["discard_after"] = $now + 120;
if ((!isset($_SESSION["loggedin"]) || !$_SESSION["loggedin"]) &&
basename($_SERVER["PHP_SELF"]) != "login.php")
{
header("Location: https://".$domain."/login.php");
die();
}
I monitored this with Burp and confirmed, that the session id changes when I log in successfully. The session ID also changes when I navigate through the site without any problem and just the way I want to.
However this behaviour is not consitent. I have some user who enter the correct credentials (I know this because of the logs) but have no valid session and can not cross the login page to the home page.
I also have the strange case that one has to log in twice (both times correct credentials) befor a valid session is set. This happens to me unpredictable as well as to other users. I could not see yet when this happens and when not, only that the login should have worked.
Some information about the setup. I have a Ubuntu 14.04 vServer with Apache2 and PHP 5.X. On the client side I use the latest version of Firefox and Chrome on Windows 7 64x. One user who can not login at all even though the credentials are correct and the code above is definitly executed is using Chrome on Windows 7 64x as well (I have no more information regarding this).
I know for sure that the problem is the session_regenerate_id(true); function because if I comment this line out everything works fine but this solution is not satisfactory to me. I also tried a PC from which I certainly never entered the website befor and there everything also works.
I can not see what causes this and the PHP man page did not really help me there. Especially the not determinstic behaviour confuses me.
I might not answer until tomorrow but I will value all useful answers and comments.
EDIT
This is the entire login sequence without unneccessary stuff that is not executed in my scenario or definitly unimportant. I never output anything befor.
if($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST["inputEmail"],
$_POST["inputPassword"]) && $_POST["inputEmail"] !== "" &&
$_POST["inputPassword"] !== "")
{
$domain = $_SERVER["HTTP_HOST"];
$passwordHash = hash("sha256", $_POST["inputPassword"]."somesecretsalt");
//Own function which definitly works
$connection = connectToDB("standard");
//Get usernames and passwordhashes for checking
$query_getUser = "SELECT id, firstname, lastname, email,
passwordhash FROM user WHERE email = ?;";
if($stmt = mysqli_prepare($connection, $query_getUser))
{
mysqli_stmt_bind_param($stmt, "s", $_POST["inputEmail"]);
mysqli_stmt_execute($stmt);
$userRAW = mysqli_stmt_get_result($stmt);
mysqli_stmt_close($stmt);
}
if(mysqli_num_rows($userRAW) == 1)
{
//State: User exists
$dataset = mysqli_fetch_array($userRAW, MYSQLI_ASSOC);
$now = time();
//This is the crucial part which is definitly executed because the
// log entry in the following if clause is executed
session_set_cookie_params(1800, "/", $domain, true, true);
session_start();
session_regenerate_id(true);
if($dataset["passwordhash"] === $passwordHash)
{
//State: User exists, correct password
$_SESSION["loggedin"] = true;
$_SESSION["id"] = $dataset["id"];
$_SESSION["email"] = $dataset["email"];
$_SESSION["name"] = $dataset["firstname"]." ".$dataset["lastname"];
$comment = $_SESSION["name"]." (ID:".$dataset["id"].") has logged in";
writeToLog("Login success ", $comment, __LINE__);
if ($_SERVER["SERVER_PROTOCOL"] == "HTTP/1.1")
{
if(php_sapi_name() == "cgi")
{
header("Status: 303 See Other");
}
else
{
header("HTTP/1.1 303 See Other");
}
}
header("Location: https://".$domain."/index.php");
mysqli_close($connection);
die();
}
}
mysqli_close($connection);
}
SITUATION
I have made the following login form:
<?php
session_start();
session_regenerate_id(TRUE);
$username = $_POST['username'];
$password = $_POST['password'];
$url_to_open_after_success_login = $_POST['sezione'];
//Connect to my database
try {
$pdo = new PDO('mysql:host=0.0.0.0;dbname=name', 'user', 'passw');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo "non riesco a connettere. perchè -> " . $e->getMessage();
exit();
}
//The table "accessi" has 2 fields that are "username" and "password"
//From this table I grab the data
try {
$query_mag = $pdo->prepare("SELECT * FROM accessi WHERE username = ?");
$query_mag->bindParam(1 , $username, PDO::PARAM_INT);
$query_mag->execute();
} catch (PDOException $e) {
echo "Unable to execute the query. ". $e->getMessage();
exit();
}
$dati_utente = $query_mag->fetch();
//CHECK IF THE PASSWORD IS CORRECT OR NOT
if ( password_verify($password, $dati_utente[1]) ) {
//login executed
$_SESSION["login"] = 1;
if ($url_to_open_after_success_login == 'something') {
header('location: /blabla/aaa.php');
} else {
header('location: /blabla2/bbb.php');
}
} else {
//WRONG PASSWORD! You are not allowed to access so go back to the home
header('location: /');
}
?>
The code above is pretty easy. I connect to the database, then I make a query to get the password (hashed of course) of a particular user. Then if the password is correct I am redirected to a page.
Only if the login successfully happened, I am using $_SESSION["login"] = 1;.
PROBLEM
On the top of each page I have the following code:
<?php
session_start();
if (!isset($_SESSION["login"])) { header('location: /error_page.php'); }
?>
<html>
<head>
//html/css/js code here...
If you look at the PHP code, you can understand that (if the user did not log in successfully) the page immediatly redirects to the error page. My question is the following.
Q: is this a safe way to check if the user logged in? should I avoid this redirect-way and try something else?
When a logged member wants to log out, I have made a logout.php file that looks like this:
<?php
session_start();
session_regenerate_id(TRUE);
$_SESSION = array();
//delete the session cookie
if (ini_get("session.use_cookies")) {
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000,
$params["path"], $params["domain"],
$params["secure"], $params["httponly"]
);
}
session_destroy();
header('location: /');
?>
A couple of points for you
After you issue a header for redirection, I would issue an exit; next, to stop execution of the script. Redirection should be the last thing you do anyways, so this ensures nothing else in your script runs accidentally.
$_SESSION is safe enough, provided your end users don't have a direct way to set or unset the data there. There's always the risk of a session hijack, but that's a different problem.
Your solution is not really safe because it missed some checks against session highjacking.
Additional you should store during the login the remote ip, remote agent and similar data on server side and compare it on every request to make (mostly) sure that the request comes from the right user.
See Proper session hijacking prevention in PHP and Preventing session hijacking
I built a PHP/MySql login system for a website I am working on and all was working fine. I took a month off from working on it, pulled it up last night, and all of a sudden it doesn't work. It recognizes if a wrong username or password was entered, but if you enter the correct information it redirects you to the login page again. Was there some update somewhere that I am unaware of? I did not change anything in any of my files. It was working perfectly a month ago, and with no change at all it doesn't work now. Any ideas?
UPDATE
It is working if I check the remember me box, but not if I don't I will paste my code below:
Login Script:
<?php
define('INCLUDE_CHECK',true);
require 'connect.php';
require 'functions.php';
session_name('TheLoginSession');
session_start();
// ---------- LOGIN ----------
if($_POST['submit']=='Login')
{
// Checking whether the Login form has been submitted
$err = array();
// Will hold our errors
if(!$_POST['username'] || !$_POST['password'])
$err[] = 'All the fields must be filled in!';
if(!count($err))
{
$_POST['username'] = mysql_real_escape_string($_POST['username']);
$_POST['password'] = mysql_real_escape_string($_POST['password']);
$_POST['remembercheck'] = (int)$_POST['remembercheck'];
$storedsaltquery = mysql_fetch_assoc(mysql_query("SELECT rand FROM members WHERE usr = '".$_POST['username']."'"));
$storedsalt = $storedsaltquery['rand'];
// Escaping all input data
$row = mysql_fetch_assoc(mysql_query("SELECT id,compid,usr,firstName,level,yn FROM members WHERE usr='{$_POST['usernamelog']}' AND pass='".hash("sha256",$_POST['passwordlog'].$storedsalt)."'"));
if($row['id'])
{
// If everything is OK login
$_SESSION['usr']=$row['usr'];
$_SESSION['comp']=$row['compid'];
$_SESSION['id'] = $row['id'];
$_SESSION['name'] = $row['firstName'];
$_SESSION['usrlevel'] = $row['level'];
$_SESSION['new'] = $row['yn'];
$_SESSION['remembercheck'] = $_POST['remembercheck'];
// Store some data in the session
setcookie('Remember','remembercheck',time()+1209600,'/','.domain.com');
}
else $err[]='Wrong username and/or password!';
}
if($err)
$_SESSION['msg']['login-err'] = implode('<br />',$err);
// Save the error messages in the session
echo header("Location: ../index.php");
exit;
}
Index Page:
<?php
define('INCLUDE_CHECK',true);
require 'includes/connect.php';
require 'includes/functions.php';
// Those two files can be included only if INCLUDE_CHECK is defined
session_name('TheLoginSession');
// Starting the session
session_start();
if($_SESSION['id'] && !isset($_COOKIE['Remember']) && !$_SESSION['remembercheck'])
{
// If you are logged in, but you don't have the Remember cookie (browser restart)
// and you have not checked the remembercheck checkbox:
$_SESSION = array();
session_destroy();
// Destroy the session
}
if(isset($_GET['logoff']))
{
$_SESSION = array();
session_destroy();
header("Location: index.php");
exit;
}
if($_SESSION['id'] && $_SESSION['new'] != 1){
header("Location: home.php");
exit;
}
?>
How can there be an update if nothing's changed?
Are you using a CMS or framework?
If it's all your own code, and you haven't changed anything, then nothing would have updated.
I've had an issue like this before but without more information, hard to know if it is the same issue. Mine had the symptom you describe (login with bad creds and get the authentication error, login with good creds and redirect back to login).
Mine was due to failing to include code to remove old session cookies. The login attempt 'works' but an old cookie also read and attempts to authenticate, fails (because it is too old), and kicks the user back to login.
If this is your issue, clear your site cookies and see if you can then log in.
If that works, you'll want to add some cleanup code to your logout and stale session handling. For instance, for logging out:
// per http://www.php.net/manual/en/function.session-destroy.php
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000,
$params["path"], $params["domain"],
$params["secure"], $params["httponly"]
session_destroy();
Again, just guessing at your issue here.
I'm using a PHP/MySQL Login Code, and I want it to store the cookie permanently (through browser closes), however it doesn't work. It logs in fine, and will remember up to a browser close, but forgets it afterwards. How can I fix this?
This is all the important code I think;
<?php
define('INCLUDE_CHECK',true);
require 'connect.php';
require 'functions.php';
// Those two files can be included only if INCLUDE_CHECK is defined
session_name('tzLogin');
// Starting the session
session_set_cookie_params(1000000*7*24*60*60);
session_start();
if($_SESSION['id'] && !isset($_COOKIE['tzRemember']) && !$_SESSION['rememberMe'])
{
// If you are logged in, but you don't have the tzRemember cookie (browser restart)
// and you have not checked the rememberMe checkbox:
$_SESSION = array();
session_destroy();
// Destroy the session
}
if(isset($_GET['logoff']))
{
$_SESSION = array();
session_destroy();
header("Location: index.php");
exit;
}
if($_POST['submit']=='Login')
{
// Checking whether the Login form has been submitted
$err = array();
// Will hold our errors
if(!$_POST['username'] || !$_POST['password'])
$err[] = 'All the fields must be filled in!';
if(!count($err))
{
$_POST['username'] = mysql_real_escape_string($_POST['username']);
$_POST['password'] = mysql_real_escape_string($_POST['password']);
$_POST['rememberMe'] = (int)$_POST['rememberMe'];
// Escaping all input data
$row = mysql_fetch_assoc(mysql_query("SELECT id,usr FROM tz_members WHERE usr='{$_POST['username']}' AND pass='".md5($_POST['password'])."'"));
if($row['usr'])
{
// If everything is OK login
$_SESSION['usr']=$row['usr'];
$_SESSION['id'] = $row['id'];
$_SESSION['rememberMe'] = $_POST['rememberMe'];
// Store some data in the session
setcookie('tzRemember',$_POST['rememberMe']);
// We create the tzRemember cookie
}
else $err[]='Wrong username and/or password!';
}
if($err)
$_SESSION['msg']['login-err'] = implode('<br />',$err);
// Save the error messages in the session
header("Location: nowloggedin.php");
exit;
}
?>
You need to set the expire time for the cookie:
setcookie('tzRemember',$_POST['rememberMe'], time()+3600);
That will make it last for one hour for example. If you don't set a time, it'll expire when the session is ended.
I've just noticed that you are setting the lifetime with session_set_cookie_params - as others have said, you're setting that way too far into the future.
It's best to stay below this year...
2038
Otherwise there will be issues and your browser will not store it.
You are setting the cookie as:
session_set_cookie_params(1000000*7*24*60*60);
Which sets the cookie to expire in 1000000*7*24*60*60 = 7*1000000/365 = 19000+ years. As far as I know, UNIX timestamp is not set for that long duration.
I have posted a question for this a long time ago, but i still can't find a answer. Basically, when a user has logged into the account and has been inactive for a while and when they return they would click something and then the system would log them out and they would have to re-login. It works 90% of the time, but sometimes it gives an error like: This page is redirecting in a way it will never complete.
But when a user clears the cookies it works fine and sometimes closing the tab and opening up a new one works too.
Here's the code:
<?php
$SUBDOMAIN = mysql_real_escape_string($_GET['p_name']);
$pname = mysql_real_escape_string($_GET['p_name']);
echo "$p_name";
include("db.php");
?>
<?php
session_start();
// Process the POST variables
$username = $_SESSION["user_name"];
//$password = $_POST["password"];
// Set up the session variables
$_SESSION["user_name"] = $username;
$ugData = $_REQUEST['p_name'];
if($_POST)
{
$_SESSION['user_name']=$_POST["user_name"];
$_SESSION['password']=$_POST["password"];
}
$secret = $info['password'];
//Checks if there is a login cookie
if(isset($_COOKIE['ID_my_site']))
//if there is, it logs you in and directes you to the members page
{
$username = $_COOKIE['ID_my_site'];
$pass = $_COOKIE['Key_my_site'];
$check = mysql_query("SELECT user_name, password FROM accounts WHERE user_name = '$username' and p_name='$ugData'")or die(mysql_error());
while($info = mysql_fetch_array( $check ))
{
if (# $info['password'] != $pass)
{
}
else
{
header("Location: home.php");
}
}
}
//if the login form is submitted
if (isset($_POST['submit']))
{
// if form has been submitted
// makes sure they filled it in
if(!$_POST['user_name'] | !$_POST['password'])
{
die('You did not fill in a required field.');
}
//checks it against the database
if (!get_magic_quotes_gpc())
{
$_POST['user_name'] = addslashes($_POST['user_name']);
}
$check = mysql_query("SELECT user_name,password FROM accounts WHERE user_name = '".$_POST['user_name']."' and p_name='".$ugData."'")or die(mysql_error());
//Gives error if user dosen't exist
$check2 = mysql_num_rows($check);
if ($check2 == 0)
{
die('That user does not exist in our database. <a href=add.php>Click Here to Register</a>');
}
while($info = mysql_fetch_array( $check ))
{
$_POST['password'] = md5($_POST['password']);
$_POST['password'] = $_POST['password'];
//gives error if the password is wrong
if (# $_POST['password'] != $info['password'])
{
die('Incorrect password, please try again');
}
else
{
// if login is ok then we add a cookie
$_POST['user_name'] = stripslashes($_POST['user_name']);
$hour = time() + 3600;
setcookie(ID_my_site, $_POST['user_name'], $hour);
setcookie(Key_my_site, $_POST['password'], $hour);
//then redirect them to the members area
header("Location: home.php");
}
}
}
else
{
// if they are not logged in
?>
</table>
</form>
<?php
}
?>
Hey, your code formatting is really bad no fun to read you might want to fix that. :)
I just had a quick look at it, erros occurring only 90% or sometimes hard to catch.
I saw you are using header("Location: home.php"); without any exit; at the end, which is generally a bad idea unless you intent to do so.
The function call header("Location: home.php"); will not stop the script from processing. The user might get the header and redirects and stops code from processing (depending on some php settings) but maybe some cookies get set before the user gets redirected. So try adding a exit; after your redirect header calls.
format you code
I would wager a guess that this has to due with the differing expire times of your session cookie, and the expire times you set for your ID_my_site and Key_my_site cookies. If not overridden, the default session timeout is 30 minutes (expressed as seconds in the settings - so 1,800). Your cookies are set to expire after an hour. So you could find yourself in a situation where the session has expired, but the other cookies are still present. Depending on the order / way you are checking things and then redirecting, you will encounter this situation if the user was idle for more than 30 minutes but less than 1 hour.
Since the only redirect you are performing in this code sample is the one to home.php, there is some sort of check occurring in that file, that is sending them on the never ending redirect spiral.
As an aside, that code sample really is very messy. You are assigning and reassigning the $username variable so often for example (and to seemingly different types of things - though I wouldn't know without seeing actual input), that it is no wonder you are having mystery issues. These few lines for example are redundant:
// Process the POST variables
$username = $_SESSION["user_name"];
//$password = $_POST["password"];
// Set up the session variables
$_SESSION["user_name"] = $username;
You're assigning $username from the session and immediately assigning it back.
From the beginning of the file:
$SUBDOMAIN = mysql_real_escape_string($_GET['p_name']);
$pname = mysql_real_escape_string($_GET['p_name']);
These two variables are assigned the same $_GET value, but it doesn't appear that $SUBDOMAIN is ever used.
And from the end of the file you are assigning the same value twice:
$_POST['password'] = md5($_POST['password']);
$_POST['password'] = $_POST['password'];
I really would encourage you to step back from your code, look at your inputs and figure out what you need to accomplish and refactor or rewrite this code entirely. With stuff like this floating around it is no wonder you have mystery bugs in your system.
Additionally, a HTTP Location header requires the URL to be absolute. You should use something like this:
$currentServerHost = $_SERVER['HTTP_HOST'];
$currentBaseURI = $currentServerHost . rtrim(dirname($_SERVER['PHP_SELF']), '/\');
header( 'Location: ' . 'http://' . $finalURI . '/home.php' );
exit;