I have a (HTTPS) login.php page which remains HTTPS (ie once user logged in goes to account dashboard). Now the problem is say the user whilst logged on to the secure dashboard clicks onto a non-sensitive page like (HTTP) about-us.php page, the session is not transmitted over HTTP as I have session.cookie_secure=1, meaning the user appears logged out on HTTP pages.
However when the user goes back to dashboard page or any sensitive account page I have been told he should still be logged in (ie from HTTP back to HTTPS)? However this is not the case and he appears logged out on the HTTPS connection too?
I believe I am missing something which is causing this problem. Here is my code:
This is PHP header file which is called to start session on login.php page:
session_start();
session_regenerate_id(true); /*avoid session fixation attempt*/
/*Create and check how long session has been started (over 5 mins) regenerate id - avoid session hijack*/
if(!isset($_SESSION['CREATED']))
{
$_SESSION['CREATED'] = time();/*time created session, ie from login/contact advertiser/email_confirm only ways for new session to start*/
}
elseif(time() - $_SESSION['CREATED'] > 300)
{
/*session started more than 5 mins(300 secs) ago*/
session_regenerate_id(true); /*change session ID for the current session and invalidate old session ID*/
$_SESSION['CREATED'] = time(); /*update creation time*/
}
/*Check if user is logged in*/
if(!isset($_SESSION['loggedin']))
{
$_SESSION['loggedin']=1;/*used to track if user is logged in on pages*/
}
/*if return false browser supports standard ob_start();*/
if(ob_start("ob_gzhandler")){ob_start();}
This is PHP header file required on every page to check if session initiated already:
session_start();
$session_errors=0;/* if>0 user not logged in*/
/*check if session is already initiated*/
if(isset($_SESSION['CREATED']))
{
if(time() - $_SESSION['CREATED'] > 300)
{
/*session started more than 5 mins(300 secs) ago*/
session_regenerate_id(true); /*change session ID for the current session and invalidate old session ID*/
$_SESSION['CREATED'] = time(); /*update creation time*/
}
}
elseif(!isset($_SESSION['CREATED'])){$session_errors++;}/*user not logged in*/
/*Check if user is logged in*/
if(!isset($_SESSION['loggedin'])){$session_errors++;}/*user not logged in*/
if(ob_start("ob_gzhandler")){ob_start();}
Also if any use this is the code to turn HTTPS of on non-sensitive pages such as about-us.php
if ($_SERVER['SERVER_PORT']!=80)
{
$url = "http://". $_SERVER['SERVER_NAME'] . ":80".$_SERVER['REQUEST_URI'];
header("Location: $url");
}
My php.ini file cookie settings
session.cookie_secure=1
session.cookie_httponly=1
session.use_only_cookies=1
session.cookie_lifetime = 0
session.save_path = /tmp
session.save_handler = files
The description by #rickchristie is good, but I think there's a better solution that he doesn't suggest. If you don't always want to use HTTPS (which does make sense sometimes; the about_us page doesn't need to be secure), you can follow the advice on the session_start page and use named sessions to continue a previous session. This is simple to use; just include the session_start calls with
session_name("MySession"); // replace with whatever makes sense
session_start();
on all secure pages.
Answered to help people who might stumble across this
As the the answer at Session lost when switching from HTTP to HTTPS in PHP has concluded, since you are using session.cookie_secure = 1 the cookie that contains the session ID is not transferred when the connection switches from HTTPS to HTTP. At HTTP connection, when you session_start(), PHP creates a new session id, which replaces the previous session id.
The answer also suggests a solution, pass the session id using query string, which is then picked up by the page. This smells of bad of security flaw. Don't forget the reason why we used HTTPS in the first place!
So the solution I suggest to you is that you redirect all http request to https counterparts. Use HTTPS for everything in your site, from css, images, to mundane static html pages. This is actually something that every application that is serious about security does. For example, visiting github page using HTTP will return:
HTTP/1.1 301 Moved Permanently
Server: nginx/0.7.67
Date: Sun, 08 May 2011 15:43:01 GMT
Content-Type: text/html
Content-Length: 185
Connection: close
Location: https://github.com/
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/0.7.67</center>
</body>
</html>
Remember why you used HTTPS in the first place, if you want to be totally secure, use HTTPS for everything.
Detect if the request is HTTPS or not (See this question) at bootstrap.
If the request is HTTP, either redirect all requests to HTTPS home page, or you can try parsing $_SERVER['REQUEST_URI'] and redirecting HTTP request to their HTTPS counterpart using parse_url and http_build_url.
Second Alternative Solution
If you really really don't want to use HTTPS for everything, then don't session_start() on pages that are accessed with HTTP. Secure cookies will be retained when you do this.
Third Alternative Solution
The other solution is to try and detect the user by IP addresses and user agent. This is not guaranteed to be accurate, so what I suggest is just use HTTPS for everything. Paypal, for example, always use HTTPS even for mundane static pages.
Related
After my login page all my other pages are inaccessible unless you are logged in. And basically to check if you are logged in I have a simple if else statement:
session_start();
if (isset($_SESSION['id'])) {
// Show the page
} else {
// Ask the user to log in
}
And for the admin pages I have an extra check:
session_start();
if (isset($_SESSION['id']) && $_SESSION['isAdmin'] == TRUE){
// Show the page
} else {
// Unauthorised access
}
Is this a safe way of protecting PHP pages?
Yes it is the safe way. and try to add <?php if(!session_id()) session_start(); ?> at the top of the page because if you have included this page in another page and session is already started in that page, the session will be canceled and this page will be prone to unauthorized users.
It depends.
All PHP session variables are stored on the server side. The moment a session is started by session_start();. PHP sets a temporary cookie on your computer named PHPSESSID set to expire at the end of the browsing session. Using this cookie PHP server assigns values to the session variables. Whenever you log out (i.e, session_destroy();), this PHPSESSID cookie value is made useless
The insecure bit about this is if someone actually stole your PHPSESSID cookie value, the person can simply set this PHPSESSID cookie on their computer and have access to your session without even entering any username or password. However this can be mitigated if you use SSL/HTTPS on your web server. It must be enforced wherever session_start(); is used. You must force SSL/HTTPS where sessions are used. If you just use SSL/HTTPS for login, and HTTP for the rest of the session, this doesn't make you safe as the PHPSESSID cookie is sent in plaintext via HTTP.
As far as I know the only way to compromise PHP's Session mechanism is to steal the PHPSESSID cookie using man-in-the-middle attacks, which can be totally made useless if you have a valid SSL certificate and use of strong cipher suite for your webserver. This cookie can also be retrieved using properly crafted XSS attacks, which can be mitigated if you filter javascript or equivalent from the PHP input to your PHP code using preg_replace with the proper regex.
create one function then call this function when you load your page.. this function return true and false if you login or not and then you can manage your URL redirection..
oR
if (isset($_SESSION['loggedin']) && $_SESSION['loggedin'] == true) {
echo "Welcome to the member's area, " . $_SESSION['username'] . "!";
} else {
echo "Please log in first to see this page.";
}
this lucks good..
I'm trying to create an auto login script. The computers are using IE8 on XP. The code successfully retrieves the user's Windows username and places it into a session, but once redirect is complete, the session is wiped clean.
In index.php:
session_start();
if (!isset($_SERVER["AUTH_USER"]) || $_SERVER["AUTH_USER"] == '') {
header('WWW-Authenticate: NTLM', false);
exit;
}
# Extract username
$user = explode('\\',$_SERVER["AUTH_USER"]);
$_SESSION['username'] = strtolower($user[1]);
print_r($_SESSION); // Success!
header("Location: index2.php");
In index2.php:
session_start()
print_r($_SESSION); // Fail. array()
The key problem seems to be the header part because during testing, I've removed it and put in a dummy username and it successfully passes to the next page. I need the header though, because it is needed to do the NTLM authentication (ie. Put the AUTH_USER details in the $_SERVER array.)
EDIT
I turned off anonymous authentication in IIS, then removed the header part and all worked. However, this creates loads of other problems.
I'd like to confirm the question posted and answered by Paul for anyone who gets stuck on this like I did.
I have multiple web sites running under IIS using PHP. Works great. Then I added a site that uses NTLM authenticated security (ie Windows Login). The session built on page 1 was not being carried forward to page 2. I dumped the $_SERVER settings, played with the INI file all to no eval. I broke the application down to the bare bones basics like Paul and confirmed that it only happens when prompting for the authentication.
To reproduce, start a new browser window, login to page 1 using winodws authentication - do not click save password, click a link to go to page 2 - no session variable. Close the browser and start again (to reset the authentication). This time remove the authentication stuff from page 1 before surfing. Goto page 2 and the session is there.
Turning off "Enable anonymous access" in the "Directory Security/Authentication and access control" property settings of my web site solved to problem.
Thanks Paul.
Add session_set_cookie_params(0) prior to starting the session. IE8 has a problem handling non-persistent cookies.
Can someone tell me why the session vars are not passing between pages? They were working up to 2 days ago. Now its not? There is a third party system that logs users in based on the third party system. I direct users to the login page with the return url. The third party system logs a user in and passes their id and a token generated on their end and returns them to my site with the id and the token in the url.
If sessions are not set i try and grab the id and the token from the url and set the sessions. (working) I then generate my own token to validate against the token passed from the third party system (working) when i go to click to another page the sessions i set are not empty (????)
Here is my code:
<?php
session_start();
// FUNCTION TO PASS THE URL THE USER IS ON SO THEY COME
// BACk TO THIS PAGE AFTER THE LOG IN. IF APPLICABLE
function curPageURL() {
$pageURL = 'http';
if ($_SERVER["HTTPS"] == "on") {$pageURL .= "s";}
$pageURL .= "://";
if ($_SERVER["SERVER_PORT"] != "80") {
$pageURL .= $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
} else {
$pageURL .= $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
}
return $pageURL;
}
// DESTROY SESSION INFO IF TIMED OUT
if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > 1800)) {
session_destroy(); // destroy session data in storage
session_unset(); // unset $_SESSION variable for the runtime
}
// SET THE SESSIONS WITH INFO PASSED FROM
// LOGIN PAGE SENT AS A GET
if(isset($_SESSION['ID']) && isset($_SESSION['token'])) {}else{
$_SESSION['ID'] = $_GET['ID'];
$_SESSION['token'] = $_GET['token'];
}
// GENERATE MY TOKEN TO MATCH THE LOGIN SYSTEM TOKEN
$userIP = $_SERVER['REMOTE_ADDR'];
$secretkey = 'A Unique Key For The Logged In User Matching the Login System Passed From mydomain.com/login.php';
$algorithm = 'md5';
$mm = date('m');
$dd = date('d');
$mmdd = $mm.$dd;
$mytoken = strtoupper(hash($algorithm, $secretkey.$_SESSION['ID'].$userIP.$mmdd));
$_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp
// THIS IS WHERE THINGS ARE GOING WRONG
// SESSION token IS NO LONG SET AFTER I Go To another page
// and my token isnt the same any more either because session ID
// is no longer set???
if($_SESSION['token']==$mytoken){}else{
header("location: https://mydomain.com/login.php?returnURL=".curPageURL());
}
?>
ok this is messed up. It has to be a problem on the hosting providers PHP setup i think because i created two pages. one called info with this code:
<?
session_start();
$_SESSION['ID'] = "112233";
$_SESSION['token'] = "mytoken";
print $_SESSION['ID'];
print $_SESSION['token'];
?>
info 2
and one called info2 with this code:
<?
session_start();
print $_SESSION['ID'];
print $_SESSION['token'];
?>
info
info created and printed the session ok. when i click the link to go to info2 the sessions dont print. Is this a hosting config problem?
As already mentioned, ensure you're calling session_start() on each page.
Additionally, are the scripts on different subdomains?? If they are you should set the INI value session.cookie_domain to .DOMAIN.EXT.
To further debug this whole situation, do some simple cookie watching. See if PHPSESSID is present as a cookie on both page requests, if it's not then this is your problem. You can't store cookies cross-domain unless you reconstruct them.
In response to your update, try doing this underneath your call to session_start():
echo session_id();
Confirm that it's the same on both pages. If not, check the value of session.cookie_domain like this:
echo ini_get('session.cookie_domain');
Is that set to anything? By default it should be blank, if it's set, especially not to your domain, this is the problem.
You can also try debugging the cookie value of PHPSESSID like I first suggested.
Check List
1. Make sure that you have used session_start(); in the next page.
2. Are you using .htaccess file?
if so remove the .htaccess file and check the same.
some time rewrite rules cause session probs...
3. If session is working fine and you have trouble only with token, then check the token sent in url is url_encoded.
it's not the hosting server issue...
check your URLs
if a user is login under "example.com" session will be stored for "example.com" and not "WWW.example.com" so if a link goes to www.example.com it will not have that session.
you can use htaccess to always set the url to "WWW.example.com" use below code for it
RewriteEngine On
RewriteCond %{HTTP_HOST} ^hemantjadhav.com$ [NC]
RewriteRule ^(.*)$ http://www.hemantjadhav.com/$1 [L,R=301]
(replace hemantjadhav with your domain name)
Check the size of the session file: (code taken from this post)
$sessionfile = ini_get('session.save_path') . '/' . 'sess_'.session_id();
echo 'session file: ', $sessionfile, ' ';
echo 'size: ', filesize($sessionfile), "\n";
If your session file has zero size, make sure there is still disk space available on your server. That was the problem I had.
Check disk space with df -h on a linux server.
The answer to this is it was a hosting configuration error. Hosting company changed something and it has worked ever since.
In my case the solution was to have different parameter names in $_GET and $_SESSION.
$_SESSION["businessid"] = $_GET["businessid"]; // Leads to problems with session.
$_SESSION["business_id"] = $_GET["businessid"]; //Works perfectly.
It sounds strange but that's my experience.
The only answer for this problem is to use session_start(); on the top of every page. It will work fine. Else you might need to contact your hosting provider about this problem.
I would add that I got caught up with the same problem, except that in my case page was behind Varnish caching proxy and I missed out that configuration had a line where cookies were allowed only on specific paths, otherwise they would get removed with the following directive:
unset req.http.cookie;
Dont forget to also check your proxy settings.
I had session.cookie_samesite = "Strict" in my runtime file and was trying to bounce my user from Oauth2.0 back to my site and the PHP session ID was getting erased when the redirects hit. I removed this from my runtime file and it works fine now.
For anyone else searching this in frustration - another thing to check is the cookie_secure setting in php.ini.
If cookie_secure=1, cookies will only be sent and persist on secure connections. In our case, the site was deployed to an environment that did not have an ssl setup yet.
Set cookie_secure back to its default (0) - or get the site secured.
Make sure both pages are on the same domain.
Even www.site.com is different than site.com
If the above solutions do not work I suggest you do the following right before you set the new session variables:
session_destroy();
session_start();
and THEN save the new session variables that were not persisting before
In case this helps others:
If sessions are closed (e.g. with session_write_close() or session_commit()), then anything written to a session after that is not persisted.
Re-opening a closed session during the same request seems at best an uncertain endeavor. If anything has been sent back to the client already, session_start() seems to fail (return false) and nothing written to $_SESSION is persisted even if errors are not thrown.
Some may wonder why one would close sessions intentionally in the first place - the reason is "performance". Session resources (e.g. files with file-based sessions) are locked while the session is "open" and so for the duration of handling a request by default unless the session is specifically closed. If a response is taking awhile on the server (e.g. a long-running report query), a user (or multi-threaded UI) cannot complete another session-locking request while one is already in progress - so effectively all the session-based requests stack up sequentially and users are stuck waiting (the opposite of what is wanted with most modern UIs). The best answer, in most of my cases, is to release (close) the session as soon as possible (typically just after is has been read for the first time when handling a request) and keep it open for the duration of the request handling only if one needs to write to the session later (cases which should be minimized for performance of course).
You did not call session_write_close()
I'm making a login page and for some reason the session will not persist between where I set it and the page where I am forwarding to. I can comment out the header in the page where the session was initialized and see that the session has the data in it. However, when I do a print_r in the target page, the session is empty.
I have already made sure that session_start is called. There is only one domain for this site and my browser is set to accept cookies. I can forward to any other page and see the session data but just not this one.
Is there something that someone can offer to help in debugging this?
$_SESSION['auth'] = $auth;
header( "Location: /" ); // commenting this out shows the data is in fact there
I want to protect the index page so I test to see if session['auth'] is set. If not, I forward over to /user/login which allows the user to login. If successful then we forward back over to the index page where it should pass the isset session test. It fails though and there is no session data.
set.php:
session_start();
$_SESSION['auth'] = true;
header('Location: /');
index.php:
session_start();
var_dump($_SESSION);
Create these 2 files and request set.php. What do you see?
If you set a session variable, then do a header redirect, you need to add session_write_close() before the redirect or you will lose your sesson modification.
Something that I've ran in to quite a bit is accidentally redirecting from a page with 'www.' in the URL to a page without. I'm not exactly sure why it happens but for some reason the session between a site is different with and without the 'www.'.
i am implementing a log-in system, i am sure a lot of you know what it is, i use sessions to store the user's ID, and check it if he access a page that needs the user to be logged in.
But my problem is when the user clicks the log-out anchor, nothing happens i still can access the other pages as long as the current page is open.
here is the code is use:
<?
unset($_SESSION["ID"]);
session_destroy();
header('location: ../Home/index.php');
?>
so anyone can help. thanks in advance.
You need to do a session_start() before session_destroy().
If you don't, PHP has no idea which session you're trying to destroy.
HTTP/1.1 requires absolute URI as an argument to Location. So it should be:
header('Location: http://example.com/home');
exit(); # just to be sure
But my problem is when the user clicks
the log-out anchor, nothing happens
A lot of things happens !
Are you trying to go back with the previous button and then accessing to the login page which log you in back ?
Are you page really checking for a session when a user try to display ?
Are you sure you are NOT displaying a cached version of your page ?
Did you check PHP sessions files are well deleted ? (maybe permission problems can occurs)
Check the location header syntax, RFC2616 14.30 says:
The Location response-header field is
used to redirect the recipient to a
location other than the Request-URI
for completion of the request or
identification of a new resource. For
201 (Created) responses, the Location
is that of the new resource which was
created by the request. For 3xx
responses, the location SHOULD
indicate the server's preferred URI
for automatic redirection to the
resource. The field value consists of
a single absolute URI.
Location = "Location" ":" absoluteURI
Try:
var_dump($_SESSION);
On each of your page, to see what, really happens.
It is likely you also have to delete the session cookie:
unset($_SESSION["ID"]);
if (isset($_COOKIE[session_name()])) {
setcookie(session_name(), '', time()-42000, '/');
}
session_destroy();
//...
On Logout page it should be like below
<?php
session_start()
unset($_SESSION["ID"]);
session_destroy();
header('Location: http://example.com/home');
?>
And on other pages that you want to restrict without a login user. You need to write following code on each page:
<?php
session_start()
if(!isset($_SESSION["ID"]) || empty($_SESSION["ID"])) {
// redirect to login page
header('Location: http://example.com/login');
}
?>