Executing code when a session ends in sails.js - javascript

Using sails.js, is there a way to run a function when a user session expires or is finished? Some configuration to do in config/session.js?
I know exists session.destroy, which you can set a function to execute when the session is destroyed, but I need it to be a global unique function for the application.
The idea would be writing in db table the state of a user as offline, when it's session ends.
Thanks.

If you're asking if there is a way to see if a user's session has expired -
Yes! It depends on how you're storing the server-side component of the session. Remember, traditional sessions require 2 pieces to work correctly - something on the client side (a cookie for example) and something on the server side to remember the user. In Sails the server-side piece is stored in the data store specified in the adapter portion of the Session Config File. You can query this data-store (even if it's the default Memory Store) and look for all users that have expired sessions.
Going deeper...
If you're asking if there is a specific method that gets called when a user session expires, then no, that's not the way sessions work. Sessions are a "hack" to make HTTP stateful. They aren't an active/live thing in the way that if they die we are notified. A session is just a record (likely a database) with a long code and a date. When the user visits your site, they give you a code from their cookie and you verify against the record in your session database. If the record matches and hasn't expired, HURRAY! you know who they are and they continue with their request. If the record doesn't match or has expired, BOO!, prompt them to log in again.
Really jumping to conclusions now...
I presume from the last sentence that you're looking to try to monitor whether someone is logged in to track "active" users. I would suggest that sessions are a poor metric of that. With sessions I can log in to your site and then leave. Depending on the length of your session expiration (24 hours or 30 days are typical values) I would be shown as logged in for that entire time. Is that a really helpful metric? I'm not using using your site but you're showing me as "logged in". Furthermore I could come back on another device (phone or another browser) and I would be forced to log back in. Now I have 2 or more sessions. Which one is correct?
If you're trying to gauge active usage I would either use Websockets (they would tell you exactly when someone is connected/disconnected to one of your pages - read more here) or just have a "heartbeat" - Each time a user visits one of your pages that visit is recorded as last seen at. This gives you a rough gauge as to who is actively on the site and who hasn't done anything in, say, over an hour.

You can do this by adding policy to all route
for example add sessionAuth.js to policy folder :
module.exports = function(req, res, next) {
// If you are not using passport then set your own logic
if (req.session.authenticated) {
return next();
}
// if you are using passport then
if(req.isAuthenticated()) {
return next();
}
//make your logic if session ends here
//** do some thing /
};
add this lines to config/policies.js :
module.exports.policies = {
'*': 'sessionAuth'
}

Related

In Node.js using Express, restrict access to a route based on user credentials

In express app where users login using their web identities (google, facebook, amazon, etc) using passport.js for this. I have created a route. but only want that a single user should have access to it.
I have it working with extensive testing, but not entirely sure if its in fact secure enough?
Here is my code for the route:
app.get("/superSecretPage", function(req, res){
console.log(req.user);
if (req.isAuthenticated()){
if (req.user.userId === "XXXXXXXXXXXXXXXX") {
User.find({}, function(err, users){
res.render("userlist", {
users: users,
});
});
} else {
res.render("invalid")
}
} else {
res.redirect("login")
}
});
XXXXXXXXXXXXXXXX = being the users uniqueID from Google/Amazon/Facebook or another ID provider
Like i said this work, and only allows the user that equals req.user.userId, but is this secure enough?
This is not a proper way to do that. What will you do If you want to allow another user later? Will you open code and edit the user Id?
Do not hard code the user ID.
You need to implement Role Base Access Control. You need to create a super power user role and assign it to the users, Who you want to allow to access your super secret page. And use middlewares to check the role permissions.
This will help you : Role based auth | NodeJS
Like i said this work, and only allows the user that equals req.user.userId, but is this secure enough?
You haven't really shown enough to know about the overall security of this. The security depends upon at least the following:
Implementation of req.isAuthenticated()
How the user session was established and protected. Most sessions use a browser cookie to identify the session and it must be run over https to offer any protection. Then, you must also have proper auto-logout to make it less likely the session is just left active where someone else can use it on that computer.
How the req.user.userId got set in the first place. You don't show this so we really have no idea what is behind that and whether it's following good security practices or not.
If there is any persistent storage of the user session, then the security of that storage mechanism is relevant.
Presuming there's a login mechanism, are secure (hard to guess) credentials required? Are there anti-hacking protections in place to attempt to thwart credential guessing.
If you are 100% sure that req.user.userId is valid and that this connection belongs to the appropriate user for the userId, then this bit of code works fine. But, the devil is in the details of making sure that req.user.userId is appropriately connected to an authorized user and that's where the hard work is of making security work.
Add a field in the db schema and set it to an array which contains all the route that the user has access to. When authenticating loop through the array to see if he/she can access the route he/she is trying to.

Safe place to store an encrypt/decrypt key using PHP and JS

I just want everyone to know that I am in no way a professional web developer nor a security expert. Well, I'm not a beginner either. You can say that I am an amateur individual finding interest in web development.
And so, I'm developing a simple, small, and rather, a personal web app (though I'm thinking of sharing it to some friends and any individual who might find it interesting) that audits/logs every expense you take so you can keep track of the money you spend down to the last bit. Although my app is as simple as that (for now).
Since I'm taking my app to be shared to some friends and individuals as a factor, I already implemented a login to my application. Although it only needs the user key, which acts as the username and password at the same time.
I've used jQuery AJAX/PHP for the login authentication, as simple as getting the text entered by such user in the textbox, passing it to jQuery then passing it to the PHP on the server to verify if such user exists. And if yes, the user will be redirected to the main interface where his/her weekly expense will be logged.
Much for that, my main problem and interest is within the security, I've formulated a simple and a rather weak security logic where a user can't get to the main interface without having to login successfully first. The flow is like this.
when a user tries to go the main interface (dashboard.php) without successfully logging in on the login page (index.php), he will then be prompted something like "you are not able to view this page as you are not logged in." and then s/he will be redirected back to the login page (index.php)
How I've done this is rather simple:
Once a user key has been verified and the user is logged in successfully, cookies will then be created (and here is where my dilemma begins). the app will create 2 cookies, 1 is 'user_key' where the user key will be stored; and 2 is 'access_auth' where the main interface access is defined, true if logged in successfully and false if wrong or invalid user key.
Of course I'm trying to make things a little secure, I've encrypted both the cookie name and value with an openssl_encrypt function with 'AES-128-CBC' with PHP here, each and every user key has it's own unique iv_key to be used with the encryption/decryption of the cookie and it's values. I've encrypted the cookie so it wouldn't be naked and easily altered, since they won't know which is which. Of course, the encrypted text will vary for every user key since they have unique iv_keys although they have same 'key' values hard-coded in the PHP file.
pretty crazy right ?. yea i know, just let me be for that. and as how the main interface (dashboard.php) knows if a user has been logged in or not and to redirect them back to the login page (index.php) is purely easy. 'that' iv_key is stored together with the user_key row in the database.
I've attached a JavaScript in the main interface (dashboard.php) which will check if the cookie is equal to 2, if it is less than or greater than that, all those cookies will be deleted and then the user will redirected to the login page (index.php).
var x = [];
var y = 0;
//Count Cookie
$.each($.cookie(), function(z){
x[y] = z;
y++;
});
//Check if Cookie is complete
if (x.length != 2) {
//If incomplete Cookie - delete remaining cookie, prompt access denied, and redirect to login page
for (var i = 0; i < x.length; i++) {
$.removeCookie(x[i], { path: '/' });
};
alert("You are not allowed to enter this page as you are not yet logged in !.");
window.location.href = "index.php";
} else {
//If complete Cookie - authenticate cookie if existing in database
}
As you can see, the code is rather incomplete, what I want to do next after verifying that the count of the cookies stored is 2 is to dig in that cookie, decrypt it and ensure that the values are correct using the 'iv_key', the iv_key will then be used to decrypt a cookie that contains the user_key and check if it is existing in the database, at the same time the cookie that contains access_auth will also be decrypted and alter it's value depending on the user_key cookie's verification (returns true if user_key is found in database, otherwise false). Then after checking everything is legitimate, the cookies will then be re-encrypted using the same iv_key stored somewhere I don't know yet.
My question is and was, 'where is a safe location to store the encryption/decryption key?' and that is the 'iv_key'. I've read some threads and things about Session Variables, Local Storage, and Cookie. And I've put this things into consideration.
SESSION - I can use session storage of PHP to store the key in something like $_SESSION['user_key'] then access it later when needed be. But I've read an opinion saying that it is not recommended to store sensitive information including keys, passwords, or anything in session variable since they are stored somewhere on the server's public directory. And another thing is the session variable's lifespan, it lasts for around 30 minutes or so. I need to keep the key for as long as the user is logged in. The nice thing I find here is that, it'll be a little bit hard to alter the value and I don't need to encrypt it (the iv_key) here since it is server sided, and hidden to the naked eye, well not unless when being hacked of course. What I mean is, they don't appear on the debugging tools just like how localStorage and Cookies are visible there.
LOCAL STORAGE - this eliminates my problem of lifespan, since it will be stored in the localStorage vault of the browser not until I close the browser. But the problem here is that the values can easily be changed via console box of the debugger tool, I can eliminate this problem by encrypting the 'iv_key', but what's the point of encrypting the encryption/decryption key? Should I encrypt it using itself as the 'iv_key' too? Or I can use base64_encode?, which eliminates the security of needing a key, and can be decrypted so easily with no hassle.
COOKIE - this one adopts two problems, one from session variable and one from localstorage. From session variable, I mean is the lifespan. As far as I've read, cookies last for about 1 hour or so, but still depends if an expiry has been declared when setting the cookie. The other is from localStorage, since it can easily be altered via console box of the debugger tools too. Although I've already encrypted 2 Cookies beforehand, but what's the point of storing the encryption key together with the values you encrypted?, should I go on with this and encrypt the 'iv_key' by itself, just like what I might do with localStorage?.
I'm lost as to where I should save this sensitive 'encryption_key' as it is crucial in encrypting and decrypting the cookies and other information my app needs.
Why am I so devastated with such security, despite having a simple worthless app?.
Well, because I know and I believe that I can use this as a two-step further knowledge which I can used with my future projects. I maybe doing web development for fun right now. But I'm taking it to consideration as my profession. And so, I want my apps to be secure in any means.

How can I check in real time if a user is logged in?

I am building a simple support chat for my website using Ajax. I would like to check if the user that I am currently chatting with left the browser.
At the moment I have build in that feature by setting interval function at customer side that creates the file with name: userId.txt
In the admin area I have created an interval function that checks if userId.txt exists. If it exists, it deletes it. If the file is not recreated by the custom interval function - next time the admin function will find out that file is not there it mark customer with this userId as inactive.
Abstract representation:
customer -> interval Ajax function -> php [if no file - create a new file]
admin -> interval Ajax function -> php [if file exists - delete the file] -> return state to Ajax function and do something
I was wondering if there is any better way to implement this feature that you can think of?
My solution is to use the jquery ready and beforeunload methods to trigger an ajax post request that will notify when the user arrives and leaves.
This solution is "light" because it only logs twice per user.
support.html
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script>
//log user that just arrived - Page loaded
$(document).ready(function() {
$.ajax({
type: 'POST',
url: 'log.php',
async:false,
data: {userlog:"userid arrived"}
});
});
//log user that is about to leave - window/tab will be closed.
$(window).bind('beforeunload', function(){
$.ajax({
type: 'POST',
url: 'log.php',
async:false,
data: {userlog:"userid left"}
});
});
</script>
</head>
<body>
<h2>Your support html code...</h2>
</body>
</html>
log.php
<?php
//code this script in a way that you get notified in real time
//in this case, I just log to a txt file
$userLog = $_POST['userlog'];
file_put_contents("userlog.txt", $userLog."\n", FILE_APPEND );
//userid arrived
//userid left
Notes:
1 - Tested on Chrome, FF and Opera. I don't have a mac so I couldn't test it on Safari but it should work too.
2 - I've tried the unload method but it wasn't as reliable as beforeunload.
3 - Setting async to false on the ajax request means that the statement you are calling has to complete before the next statement, this ensures that you'll get notified before the window/tab is closed.
#Gonzalon makes a good point but using a normal DB table or the filesystem for constantly updating user movement would be exhaustive to most hard disks. This would be a good reason for using shared memory functions in PHP.
You have to differentiate a bit between the original question "How do i check in real-time, if a user is logged in?" and "How can i make sure, if a user is still on the other side (in my chat)?".
For a "login system" i would suggest to work with PHP sessions.
For the "is user still there" question, i would suggest to update one field of the active session named LAST_ACTIVITY. It is necessary to write a timestamp with the last contact with the client into a store (database) and test whether that is older than X seconds.
I'm suggesting sessions, because you have not mentioned them in your question and it looks like you are creating the userID.txt file manually on each Ajax request, right? Thats not needed, unless working cookie and session-less is a development requirement.
Now, for the PHP sessions i would simply change the session handler (backend) to whatever scales for you and what makes requesting information easy.
By default PHP uses the session temp folder to create session files,
but you might change it, so that the underlying session handler becomes a mariadb database or memcache or rediska.
When the users sessions are stored into a database you can query them: "How many users are now logged in?", "Who is where?".
The answer for "How can I check in real time if a user is logged in?" is, when the user session is created and the user is successfully authenticated.
For real-time chat application there are a lot of technologies out there, from "php comet", "html5 eventsource" + "websockets" / "long polling" to "message queues", like RabbitMq/ActiveMq with publish/subscribe to specific channels.
If this is a simple or restricted environment, maybe a VPS, then you can still stick to your solution of intervalic Ajax requests. Each request might then update $_SESSION['LAST_ACTIVITY'] with a server-side timestamp. Referencing: https://stackoverflow.com/a/1270960/1163786
A modification to this idea would be to stop doing Ajax requests, when the mouse movement stops. If the user doesn't move the mouse on your page for say 10 minutes, you would stop updating the LAST_ACTIVITY timestamp. This would fix the problem of showing users who are idle as being online.
Another modification is to reduce the size of the "iam still here" REQUEST to the server by using small GET or HEADER requests. A short HEADER "ping" is often enough, instead of sending long messages or JSON via POST.
You might find a complete "How to create an Ajax Web Chat with PHP, jQuery" over here. They use a timeout of 15 seconds for the chat.
Part 1 http://tutorialzine.com/2010/10/ajax-web-chat-php-mysql/
Part 2 http://tutorialzine.com/2010/10/ajax-web-chat-css-jquery/
You can do it this way, but it'll be slow, inefficient, and probably highly insecure. Using a database would be a noticeable improvement, but even that wouldn't be particularly scalable, depending on how "real-time" you want this to be and how many conversations you want it to be able to handle simultaneously.
You'd be much better off using a NoSQL solution such as Redis for any actions that you'll need to run frequently (ie: "is user online" checks, storing short-term conversation updates, and checking for conversation updates at short intervals).
Then you'd use the database for more long-term tasks like storing user information and saving active conversations at regular intervals (maybe once per minute, for example).
Why Ajax and not Websockets? Surely a websocket would give you a considerably faster chat system, wouldn't require generating and checking a text file, would not involve a database lookup and you can tell instantly if the connection is dropped.
I would install the https://github.com/nrk/predis library. So at the time the user authenticates, It publishes a message to Redis server.
Then you can set-up a little node server on the back-end - something simple like:
var server = require('http').Server();
var io = require('socket.io')(server);
var Redis = require('ioredis');
var redis = new Redis();
var authenticatedUsers = [];
// Subscribe to the authenticatedUsers channel in Redis
redis.subscribe('authenticatedUsers');
// Logic for what to do when a message is received from Redis
redis.on('message', function(channel, message) {
authenticatedUsers.push(message);
io.emit('userAuthenticated', message);
});
// What happens when a client connects
io.on('connection', function(socket) {
console.log('connection', socket.id);
socket.on('disconnect', function(a) {
console.log('user disconnected', a);
});
});
server.listen(3000);
Far from complete, but something to get you started.
Alternatively, take a look at Firebase. https://www.firebase.com/ if you dont want to bother with the server-side
I would suggest using in built HTML5 session storage for this purpose. This is supported by all modern browsers so we will not face issues for the same.
This will help us to be efficient and quick to recognize if user is online. Whenever user moves mouse or presses keys update session storage with date and time. Check it periodically to see if it is empty or null and decide user left the site.
Depending on your resources you may opt for websockets or the previous method called long pool request. Both ensure a bidirectional communication between the server and the client. But they may be expensive on resources.
Here is an good tutorial on the websocket:
http://www.binarytides.com/websockets-php-tutorial/
I would use a callback that you (admin) can trigger. I use this technique in web app and mobile apps to (All this is set on the user side from the server):
Send a message to user (like: "behave or I ban you").
Update user status/location. (for events to know when attendants is arriving)
Terminate user connections (e.g. force log out if maintenance).
Set user report time (e.g. how often should the user report back)
The callback for the web app is usually in JavaScript, and you define when and how you want the user to call home. Think of it as a service channel.
Instead of creating and deleting files you can do the same thing with cookie benefits of using cookie are
You do not need to hit ajax request to create a file on server as cookies are accessible by javascript/jquery.
Cookies have an option to set the time interval so would automatically delete themselves after a time, so you will not need php script to delete that.
Cookies are accessible by php, so when ever you need to check if user is still active or not, you can simply check if the cookie exist
If it were aspnet I would say signalR... but for php perhaps you could look into Rachet it might help with a lot of what you are trying to accomplish as the messages could be pushed to the clients instead of client polling.
Imo, there is no need for setting up solutions with bidirectional communications. You only want to know if a user is still logged in or attached to the system. If I understand you right, you only need a communication from server to client. So you can try SSE (server sent events) for that. The link gives you an idea, how to implement this with PHP.
The idea is simple. The server knows if user is attached or not. He could send something like "hey, user xyz is still logged in" or "hey, user xzy seems not to be logged in any more" and the client only listens to that messages and can react to the messages (e.g. via JavaScript).
The advantage is: SSE is really good for realtime applications, because the server only has to send data and the client has only to listen, see also the specification for this.
If you really need bidirectional communications or can't go with the two dependencies mentioned in the specs, it's not the best decision to use SSE, of course.
Here is a late Update with a nice chat example (written in Java). Probably it's also good to get an idea how to implement this in PHP.

Close server-side chat connections before unload in javascript

On my website, I have built a chatroom with support for multiple rooms. When a user joins the room, a session is placed into the database so that if they try to join the room again in another browser window, they are locked out.
It works like this
1. Join the chatroom page
2. Connect to chatroom #main
If the user has a session in the database for #main
--- Block user from joining
else
--- Load chatroom
When the chatroom is closed client side or the user terminates there connection with the /quit command, all of their sessions are deleted, and this works fine.
However
There is a possibility that users will just close the browser window rather than terminating their connection. The problem with this is that their session will stay in the database, meaning when they try to connect to the room, they are blocked.
I'm using this code onbeforeunload to try and prevent that
function disconnect() {
$.ajax({
url: "/remove-chat-sessions.php?global",
async: false
});
};
This is also the function called when the user types the /quit command
The problem
The problem with this is that when I reload the page, 5 times out of 10 the sessions have not been taken out of the database, as if the ajax request failed or the page reloaded before it could finish. This means that when I go back into the chatroom, the database still thinks that I am connected, and blocks me from entering the chatroom
Is there a better way to make sure that this AJAX call will load and if not, is there a better alternative than storing user sessions in an online database?
Edit:
The reason users are blocked from joining rooms more than once is because messages you post do not appear to you when the chatroom updates for new messages. They are appended to the chatroom box when you post them. This means that if users could be in the same chatroom over multiple windows, they would not be able to see the comments that they posted across all of the windows.
In this situation you could add some sort of polling. Basically, you request with javascript a page every X time. That page adds the user session to the database. Then there's a script executing every Y time, where Y > X, that cleans old sessions.
The script that is called every X time
...
// DB call (do as you like)
$All = fetch_all_recent();
foreach ($All as $Session)
{
if ($Session['time'] < time() - $y)
{
delete_session($Session['id']);
}
}
The script that javascript is calling every X time
...
delete_old_session($User->id);
add_user_session($User->id, $Chat->id, time());
The main disadvantage of this method is the increment in requests, something Apache is not so used to (for large request number). There are two non-exclusive alternatives for this, which involve access to the server, are:
Use nginx server. I have no experience in this but I've read it supports many more connections than Apache.
Use some modern form of persistent connection, like socket.io. However, it uses node.js, which can be good or bad, depending on your business.

how to detect authentication timeout from client script

I have an ASP.NET application that is using forms authentication with a timeout set to five minutes. On my page I have a button, that when clicked, makes an AJAX call to an operation that lives on the service named in my .svc file. How do I know, from the client javascipt that the application has timed out? Or, how can I detect this in the global.asax; maybe in the application_beginrequest?
If you're talking about the session timeout. When this occurs, the IHttpSessionState.IsNewSession property should be set to true.
If you're referring to the auth timeout, then you have to check the AuthenticationTicket for expiration.
A variation on your approach: have a separate client script that first checks for authentication expiration by requesting a special page/handler which returns JSON structure to indicate the authentication status of the current user. Only after knowing that the user is still active do you then run your main ajax action. It's one more request but keeps you from entangling the timeout logic with the main ajax logic. You can also use separately in a "warning, your session will time out in x minutes" popup.
See this question and my answer there for more details about how to set it up, but the key point is that if you don't want the check for expiration to extend the sliding expiration you have to configure the expiration page/handler as a separate virtual directory with forms authentication set with slidingExpiration=false.

Categories