I have a PHP application that stored the session ID of a user upon login in a MYSQL table, which is removed when the user logs out and their session is destroyed through the logout process. the User is not allowed to log in again if the MYSQL table still has a value in that session_id column. This works great in case of naturally triggered logouts. However when the user simply closes the browser window/tab, it seems that the server is retaining the session variables and moreover since the natural logout.php was not invoked the session_id column in the MySQL table is also not getting emptied out. AS a result, I can type in any of the URLs that are protected by the login from the same computer and get right in. This is a security issue - triggered by a user who did not follow the instructions of logging out naturally instead of just closing the browser window.
I have followed the SO thread here and have tried to use the onbeforeunload() JS function to handle this situation of a browser close. As you know the onbeforeunload() event gets triggered when any of these 4 events occur - (1) browser close (2) navigating away from the page to another page by clicking on a "" link (3) refreshing the page (4) submitting a form.
In the code below I am having the following problems in (1) and (3) and I am having a hard time figuring it out :
Prob 1. When I close the browser window, I get that alert with "Stay On the Page " and "Leave Page" options. However that AJAX call to call_my_special_script.php is occurring on both options, when it should not occur in case of "Stay On The Page". call_my_special_script.php simply removes the contents of the session_id in the MySQL table.
Prob 2. When I refresh the browser - Safari / IE the code says nothing should happen, but I am getting that alert show up when I am not expecting it. Regardless of my choice on the alert it is calling call_my_special_script.php and removing the session_id value.
Any ideas what I should be doing here to fix these problems?
<script>
var validNavigation = false;
function browserCloseEvents() {
var dont_confirm_leave = 0;
var leave_message = 'You sure you want to leave the page?'
function goodbye(e) {
if (!validNavigation) {
if (dont_confirm_leave!==1) {
if(!e) e = window.event;
e.cancelBubble = true;
e.returnValue = leave_message;
if (e.stopPropagation) {
e.stopPropagation();
e.preventDefault();
}
$.ajax({
type: 'GET',
url: "call_my_special_script.php",
async: false,
success: function () {
alert("sucess");
}
});
return leave_message;
}
}
}
window.onbeforeunload = goodbye;
$(document).bind('keypress', function(e) {
if (e.keyCode == 116){
validNavigation = true;
}
});
$("a").bind("click", function() {
validNavigation = true;
});
$("form").bind("submit", function() {
validNavigation = true;
});
$("input[type=submit]").bind("click", function() {
validNavigation = true;
});
}
$(document).ready(function() {
browserCloseEvents();
});
As always, you should never base your application's security on some client side feature/function. Since they can(will) easily be bypassed.
In your case you can just make the session time out to 15 minutes and while the user is logged in just send an AJAX beacon request to reset that timer say every 5 minutes so, when the user is browsing your site then he will be logged in, if he closes the tab accidentally/intentionally, he will still be able to just reopen your site and still be logged in but only within 15 minutes of timespan. after which he shall have to re login, since his session is expired.
I've seen various CMS use this technique.
Also you can piggyback on other requests too like some AJAX call to check new messages ..etc. Like the StackOverflow does, maybe.
What I wouldn't do, and why
In my opinion, you shouldn't rely on JavaScript at all in this case, for the following reasons:
JavaScript might be disabled in the first place.
It might take only a single JS error on the entire page to disable the "logout routine".
The browser might crash.
There is no way of reliably telling whether the user actually left your page or not.
You'd have to consider a multitude of browser and operating system behaviours too.
Examples:
If I open your page in two tabs and close only one of them, I still get logged out.
Hitting F5 on a Mac doesn't do anything (at least in Chrome). But if I do that on your page, it thinks I'm reloading it, and disabled the logout routine. I can then happily proceed to close the tab without being logged out.
Hitting CtrlR on Windows or CmdR on Mac does reload a page in Chrome, but your website would log me out when doing that.
Hitting Del navigates one page back in most browsers on Windows. The last page might or might not be on your website, but I'm getting logged out either way.
Also, I consider this very bad practice:
the User is not allowed to log in again if the MYSQL table still has a value in that session_id column.
I've seen people trying to justify this with "security reasons", but it really doesn't add anything.
If there was an attacker who stole your username and password, it would prevent them from logging in while you are logged in, but it would also prevent you from doing the same while they are logged in!
(Also if someone has your password, security has long been breached.)
And if they stole your session cookie, it wouldn't protect you at all.
The only thing it does is annoy you when you're logged in on device 1 and want to log in on device 2.
What I would do instead
Let the user re-login at any time, overriding the old session.
Associate the session in your database with an expiration timestamp.
Once that timestamp has been crossed, the session cookie is no longer accepted and the user has to log in again
Depending on what you want, you could either use something like "time of login + 2 hours", or "time of last seen + 15 minutes" (which you would have to update on every page load, ofc).
Set no explicit expiration date for the session cookie, so according to PHP's setcookie function it should be deleted when the browser is closed.
Some browsers might not do this, but that's what the expiration in your DB is for.
(If you want to prevent session hijacking:)
Associate the session in your database with the user's IP.
If the session cookie matches, but the IP doesn't, the user has to log in again.
A (somewhat expensive) alternative
The easiest way of telling when a user "has gone away" is if you have an open connection, which closes when the user leaves.
This is not the case with HTTP(S) - it is based on subsequent requests.
This is the case, however, for WebSockets.
Now, the idea would be:
When the user loads the page, a WebSocket is opened.
Every 10 seconds (or so) the browser posts a message to the server.
As long as there is at least one WebSocket open for a user, and it has posted a message in the last 30 seconds (or so), the user stays logged in, otherwise their session is discarded.
For older browsers, you could add an AJAX fallback, which would also work, but generate a lot more traffic than WebSockets.
Upsides:
The window of opportunity for an attacker is drastically reduced.
Multiple tabs are no longer an issue.
Downsides:
Generates quite a bit of traffic.
Will log the user out when they lose their connection to the server, even when they don't close their browser.
Related
I have a requirement that after closing the browser when user open site it should ask for login by default.
I destroyed the session values on logout button so when user clicked on logout button it works fine but if user directly close the browser or tab the session are not destroying.
I have also tried to set session.cookie_lifetime value to 0 but its not working.
The best way to do this in my opinion is the store the session with the time in it, you can create a javascript heart beat which will keep the time updated every x seconds and as look as now is never a larger time than time+x seconds then you will have your heart beat. If the time surpasses it the session will time out and you're off the the races.
On login:
session_start();
$_SESSION['last_action'] = time();
An ajax call every few (eg 20) seconds:
windows.setInterval(keepAliveCall, 20000);
Server side keepalive.php:
session_start();
$_SESSION['last_action'] = time();
On every other action:
session_start();
if ($_SESSION['last_action'] < time() - 30 /* be a little tolerant here */) {
// destroy the session and quit
}
Browsers are an implementation of web standards. They have differences between them as to how they choose they decide to implement them and can sometimes differ from the standard.
If you set a session/temporary cookie, the idea should be that it will be deleted as soon as the website is closed. However, browsers don’t always follow this as gospel. They have convenience features which can keep the cookies and restore the user's session. This could be useful if the browser suddenly crashed or a user accidentally shut down the tab.
On the other hand, for developers, this creates meddling which is not how they should behave. This isn’t the sort of thing that can be controlled so you can’t really delete a cookie when a tab is closed. The only way to solve it is to store a timestamp in a session or another cookie and anytime a page is loaded, check to see if a reasonable timestamp has passed, after which case, the cookie could be destroyed. It’s not an ideal solution, but it is the only way to implement it in modern browsers.
I know there are many threads regarding PHP sessions while ajax queries etc...
but my problem is,
I have an ajax grid (build after the page load), which I allow to edit only when use is logged on. I don't mind for session to be not checked until user actually change the page (then valid_session.php is called),
but I have an issue, when next day user opens the browser on the same page - the grid is still editable! obviously if I refresh the page, then user get logged out.
I have no-cache set on my pages, but browsers (in particular chrome) don't reload it on open.
I can't get my head around as how to force it to refresh on reopen. please guide me to the right direction...
EDIT
BTW - I found a way to handle this. I simply call session_destroy(); in session_destroy.php on unload() via $.get():
$(window).unload(function() {
$.get('session_destroy.php', function(data) {
alert(data); // alerts me of some var set to 0 - meaning session is destroyed.
});
});
To log out the user actively i think you should do some kind of polling and then trigger a logout automatically when the session expire. Or print an error message like "Changes done to this page will not be saved as the session has expired".
Obviously the grid can't now "By magic" that the session has expired, you have to tell it somehow. In any case even if the grid it's still editable, it shoul dbe impossible to save changes, otherwise there is a design flaw (like not checking if the user is logged in before saving)
One solution is to set a "last refreshed" cookie, and have a javascript setInterval() which checks if the cookie is older than, say 20 minutes. If it is, the javascript triggers a refresh. Of course, you still need to log them out after the inactivity period.
I know this question have been asked lot of times that how to track online users on a site using php , what i do is very basic if a user is logged in to my site i save their data to a database and once they click logout i destroy their session and delete that username from my database.
The real problem occurs when a user directly close the browser coz than i have no way to run a mysql query to my database and looks like they are still logged in though they are not.
I don't want to set any time to destroy cookies or sessions because that is not the appropriate way to do it let say i set time to 30min and a user closed the browser in just a min , so for 29 min he will appear online so i don' t want that.
Thanks
Use web-socket i.e.: http://html5demos.com/web-socket when your user closes the browser, the connection will be interrupted, then you set it as offline, but will only work on modern browsers.
However you still can do something like web-socket using push-stream to monitor your users.
But, if you use sessions, you can setup your timer diconnect to the same time that the session disconnects. PHP is 15 minutes as default (you can customize). So if your user keep your site open by this time but don't make requests, after this time, his session will be closed, even if the browser still open.
There is better solution, use JavaScript to send an AJAX request to your server on "onBeforeUnload" event. This way the script will ensure the session and DB record are only deleted when the user is leaving the website.
<script type="text/javascript">
$(window).on('beforeunload', function() {
$.ajax({
url: /controller/action/clear
});
});
</script>
you must store also time when user was reload page. after authentication, after click some link or something else, you must store/update in database all this actions.
after this, you should check that, if user was visit on site or was reload page about 15 minute ago, that he is not online.
i have a client side jquery script that logs the user off after 5 mins of inactivity. The problem is though is the user navigates away without logging out the session stays active. If the user closes the browser shouldnt that destroy the session since sessions stay alive for the duration of the browsers being open or the user logs off?
anywho this is what i have
(function($){
$(document).bind("idle.idleTimer", function(){
document.location = "orders.php?action=logoff&session=timeout";
});
//var minute = 60000; //1 minute is 60,000 miliseconds.
var minute = 300000; //5 minutes
var timeout = minute;
$.idleTimer(timeout);
})(jQuery);
how can i implement a server side if the user navigates away? I was thinking of using cron but then that would be not the right way (im thinking but then maybe im wrong)
i read this post
User Inactivity Logout PHP
and i don't see how the session can still take effect if the user navigates away
Navigating away necessarily doesn't expire the session, its closing the browser that does.
I would implement the check on the server side.
If the session is invalid, you should send down a 400 HTTP status code, which your JS code can use to identify that the user is no longer allowed to use the resource and hence redirect to the login page.
Set cookies expiry values to something that suits your application better.
Sarmen, the easiest way is to use the php session garbage collection to suit your need:
http://www.php.net/manual/en/session.configuration.php#ini.session.gc-maxlifetime
300s will meet your requirement.
All you need to do is add some code to your orders.php file.
What you need to do is have a few if statements checking for your $_GET variables of action and session.
If both of those requirements are met then you just need to destroy your session with session_destroy();
you can also redirect them to any page if you would like using header();
I have a web app game and while in the game I want to have it so if a user closes the page or their browser, it will automatically log them out. I tried using the onbeforeunload event attached to the window:
window.onbeforeunload = function() {
// perform logout functions here
}
The problem is, that will also fire if the user refreshes the page. Is there a way I could detect whether or not the user is completely closing the whole page, or just refreshing it?
There is not a detectable difference. To automatically logout a user, you should set an expiration on your cookie storing the login or session information. So if you set it for 1 hour, the user would essentially be logged out after that time since the cookie would be destroyed. If you wanted to postpone this auto logout while they are still interacting with the site, you could reset the expiration of the cookie every time they perform some sort of action (clicking a link, activating an AJAX call, etc). That would mean that they'd be logged out after 1 hour of inactivity as opposed to just 1 hour from login, which sounds more like what you want.
If you set the cookie's expiration to 0, then it will expire it after the session ends. That usually occurs when the user quits their browser entirely. That's another option as well.
As said, you cannot. Even worse, this event have been abandoned by lot of browsers, probably because it have been abused by malicious scripts doing pop-under and such.
A possible workaround is to have an Ajax script "phoning home": if it is silent for some time, the user just abandoned the site (closed page or browser).
Have the onunload event send a request to the server which will cause the session to expire in n seconds (where n is the maximum time for a page reload request to occur, so perhaps 10). Then have the script for the site check to see if that event is scheduled and if so, cancel it. This would give you the behavior you seem to want.
But yeah, I'd recommend simply having the session expire.
If I'm not mistaken Javascript should have a function named something like onWindowClose, maybe try searching for it?
Regarding PHP solutions, I'm not sure if there are any but I suggest you take a quick look into PHP Connection Handling, specifically the connection_aborted() and register_shutdown_function() functions.