I am a novice php programmer building a multiuser application in codeigniter.
Now, my boss has told me to look into the ability to log out people based on their changed user access privileges.
Fx. A guy is logged in as a semi admin, but has just been demoted by a real admin to regular user status. Now the semi admin should supposivly be logged out when that happens but this is where my problem occurs.
I can think of a few ways to do this but they all revolve around doing checks that will be redundant in most cases (this is a rare situation but it has occured, i have been told)
My best bet at the moment is to log all the active users in a session db and force them to relog in if their user role changes.
This however is going to generate a lot of trafic on the server for a rare "problem" as the user session data is more fittingly put into a regular session.
So my question in short is, how can i log out a user when his user privileges are changed, without working my server too hard.
Thanks in advance!
You can check if privileges have changed periodically, like once every 10 minutes, this should reduce the amount of "useless" queries and still ensure that there is an acceptable response time to a logged in user privileges being changed.
Add a javascript listener on the page then, when the super admin changes the semi-admin privileges to a normal user, trigger the logout event. Make sure that the app has javascript enabled, otherwise it won't work. This solution is used by many ACL-based apps.
Related
I am creating an admin panel to log breakdowns, save tasks, log errors and much more. I currently have the following piece of code at the top of the screen which checks if a user is logged in, if not they are sent to the login / create a user page.
<?php
session_start();
include 'login/config.php';
if(!isset($_SESSION['username'])){
header('location:login/index.php');
exit();
}
?>
I feel that there may be better ways of doing this and also more secure ways.
A username and password are required to login and get to the initial dashboard and user status levels & permissions will be added later on.
QUESTIONS::
How can I make the system more secure by improving the code or adding additional security features?
AND
How can I log to my SQL database when a user logs in and out of the admin system?
As for security, I'm no expert there, so I'll rather wait and see what the other people tell you, since it's a very interesting topic. But I'll give you my thoughts anyway.
First of all, you should take care of SQL injections on your login, always validate the input data from the users, specially on CRUD operations. I think protecting your pages with sessions should be good enough, as long as the login itself is secure, for example you could implement a system that would block the IP after few failed attempts to login etc...
About the second part, you can create a table i.e. userlog which would contain the fields you want, user_id, action(login/logout), time.
Then everytime the user does login/logout, you just insert a new record to the table. That piece of code would be located where you set/unset the session.
Not sure about the efficiency of this method, but this is a way to implement what you are saying.
you can create table like login_history which have field loginTime and logoutTime as per system time. When user login,loginTime inserted and when he logout record updated with logoutTime.
I have written a system in which a background PHP process (written using the RabbitMQBundle) processes messages from a message queue. The worker process updates user accounts. This may include a change in the user roles.
The problem is that a user won't notice any changes in his roles while being logged in. The new roles only get applied after logging out and in again. From a security perspective this is not desirable. A user should loose any role as soon as an administrator takes away privileges from that user in the backend system.
The question is: How can a session for a specific user be updated with the new roles? Or when that is not possible, how can the session be invalidated?
Note that in the background process we don't have an active security.context or request that we can use. Code like this therefore doesn't work:
$this->get('security.context')->setToken(null);
$this->get('request')->getSession()->invalidate();
You can solve this in several ways:
1) via security.always_authenticate_before_granting
You can force Symfony to refresh user on each request, effectively reloading all roles with it.
See this SO question/answer:
Change the role of a distant user without having to relog
2) Via EquatableInterface:
You need to implement isEqualsTo(User) which in turn should compare everything with User class, including roles.
See this link: Create a User Class
3) Finally, you can use DBMS to store sessions. Then, it's just matter of find the record and delete it.
I have developed a web application in PHP for a client. The client is now renting out access to the system to another company on a per user basis.
Is there a way to prevent the secondary company to use a single login and give it to 20 people to use at the same time? I know one can get the IP address of the client machine that is being logged in from, but this is obviously not very reliable method. The answer probably lies in a combination of cookies and tracking things in a database, but my brain gets a bit stuck thinking on how to implement a strategy here.
Create a unique session ID when a user logs in and store that in the DB. Add something to the session authentication code (run on all page visits) that checks that the user's session ID is equal to the one in the DB and if not, log them out. Then your web app will be accessible by only one user at a time.
To be completely honest though, can't you raise this issue with your client?
No way to tell if the login is shared among 20 people. You can restrict access by blocking simultaneous usage thru session cookies.
Most of all, protect yourself with a published Terms and Conditions document. Violation of which - revokes any standing agreement/contract. And sue them if you can provide evidence (logs) that they violated it.
Make sure you bind one user to one session. In that way you can generate a warning screen if somebody uses the same login with another session. You can then let the user choose to close the other session.
In that way you can make sure two users are not using the system at the same time. It's a bit like a software program you have installed on a computer: multiple users can use it, but only one at a time. This is probably fine.
If you don't want that, you should try to bind the login more firmly to the user: make sure he logs in with a personal e-mail address, and he gets notifications (if applicable) via e-mail. Also let the user set personal configurations. In that way you create extra value for users to have their own account.
If you have a login you have authentication, and you write any user id in session, make sure that only one session with this id created, if the session already exists throw error message.
The only problem you will have in case and user did not logout properly, instead of it pressing x button on browser then he will not be able to login till session s not expired.
There's a site with registered users area, they all have their own user/pass.
The problem is, some of then try to share the authentication info with others to help them finish their job.
There's no posibility to restrict by ip adress because there's a dynamic-ip provided for everyone.
What could be the best solution? store sessions in the database? how to restore if they don't logout properly?
Thanks
I usually let them ping-pong: A custom session_save_handler which stores the session in a database, with an extra field for user-id (session_id char, session_data blob, session_user int or char). A successful login-attempt destroys / deletes all other other sessions with that specific user-id, and you could even log the number of times this DELETE statement actually deletes rows, with a counter somewhere to block people clearly excessively 'deleting' sessions. People switching computers / locations / browsers still can get work done instantly after login, users sharing authentication will keep on logging each other out, and increasing your counter until some arbitrary limit you deem appropriate, in which case you can disable / lock out the account.
If some people are sharing their ilogin/password then there is little you can do.
You could detect that someone is connected from two different locations and then close both sessions, but that wouldn't solve the full problem.
I agree with Loïc Février that there is little you can do when they are sharing logins.
If you really want to restrict user access from multiple locations, when you detect 2 sessions of the same user you could send some sort of a code/passkey thru email and only the real owner of the account could continue.
There is no particularly efficient way. That said, one technique could also be to use a DB to store the last IP used to sign in on an account, ping the DB every X amount of time and if the client IP doesnt match the last IP used to login, end their session..
You could also track IPs used to access an account, and limit each user to say, three. If they want another (as may legitimately happen), or if they exceed this amount- you have to be contacted/approve. This is a passive method, but will ensure you are notified over suspected account sharing..
Business solution
Make guidelines that it's not allowed to share logins to anyone. Track all login operations and if you see concurrent access, block the user.
a) The blocked user will call you, crying his login won't work: Give second and last chance. If it's not taken -> tell the boss. If you're the boss -> fire.
b) The blocked user will not call you. I wonder how he could work now. -> tell the boss. If you're the boss -> fire.
Programming solution
On the login screen, set a flag (the IP address?) in the database that the user is logged in at the moment. On logout, reset the flag. If the user is logged in, don't allow login. If the user does not log out correctly, the flag will still be set. So define a timeout for the flag to. About 5 min should be OK. It would be no gain for anyone to share login, as he would always have to login again, when you perform a check on every page access.
How should I design a login system so that each username can only be logged on in one place at a time? I want to keep users from giving their username to someone else to login so they can avoid paying for each user.
If a user is already logged in and tries to log in on another machine should I block the 2nd login (which could be a problem if the user was logged on at work and then tried to get on at home)? Or should I allow the 2nd login and end the 1st login? Or does anyone have a better suggestion?
Some Instant Messengers (that can work only with one logged in endpoint) have a nice way of sorting out such conflicts. They show a message like
You are already logged on from <COMPUTERNAME>
(in case of a web app, that would be <IP/Browser>)
and give you a choice between
either leaving that logon alive (and not log on from the machine you're on), or
ending the existing logon (and logging on on the current machine).
This is technically the most challenging, but definitely the most friendly way - it ensures a user has only one session running, without being too obvious about it. And there is no bad blood with users unable to log in because they forgot to log out at work, etc.
Blizzard's World of Warcraft I believe implements this beautifully.
Basically, if you try to sign into the game after already being signed in, the first connection is kicked off.
This basically just entails making the session stored on the database. When you store the session data, store a username too. When a user logs in, delete any session records with that users name, and then create a new one for the person logging in.
I wouldn't suggest blocking 'new' people trying to log in, because users don't want to have to go back to another computer they have (possibly miles away) just because they forgot to log out.
There are also some other things you might have to think of. Things like sessionid hijacking. If a user just puts a cookie on their system (which is always possible) with the right sessionid, it is possible that they could use the same session on multiple computers. In which case you'd probably want to keep an IP field where you keep the data on who is currently logged on.
A typical approach to this problem is to use an
inactivity time-out period.
This system enforces a maximum number of logins per account, while allowing for the situation mentioned: a user left the office without logging out, and attempts to login from his/her home workstation.
Here are the general lines of such a system
Each account is associated with a number of concurrent logins (aka "seats") allowed (it seems the OP wished one and only one, for every account, but this could be more, and vary on an account basis).
The license manager logic keeps a list of all accounts/users currently logged-in, along with a time stamp with their "last" activity.
Before serving any page, the web application, calls the license manager (LM). The purpose is to allow the LM to update the timestamp of "last" activity, but also to deny the call in case the license was taken (more on this below)
Upon each login, the license manager logic verifies that the number of seats taken doesn't exceed the amount specified for the account.
If that is not the case, the LM simply adds the current session to the list of active session
If that is the case, the LM check for sessions in the list which are older than the time-out period. If one is found, it disables it, and grants access to the new login. If none is found, the login is denied.
upon each [explicit] log-out, the LM removes the corresponding session from the lists of active session.
Note that the general principle outlined above can have some variations, in particular:
rather than silently and systematically invalidating the [typically oldest] timed-out session, one can inform the user currently attempting to logging about this situation and let him/her decide of the need to "kill" such a session.
To avoid burdening the LM with each and every new page request, the web application can keep track on a per-session basis of the time since the session was last "refreshed" in the LM, and only call the LM if such time exceed say 1/3 of the time-out period.
Independently from the LM logic per-se, remember to keep a log of all the LM-related events (logins, logouts, inactive session "kills", refused logins...). Such logs should include the date/time, the IP address and other relevant info, and are useful when resolving issues associated with stolen passwords and such. Such logs also contain invaluable marketing, for example to find all accounts which appear to have too few seats (and could therefore purchase some ugrade), or to find at-risk accounts etc.
A few more considerations
make it easy for users to log-out (log-out button/link on most every page, at a fixed location
make it easy for users to report conflict / stolen password situation
Block the first login. If you log in at home, then in work, you don't want to be blocked, since this is a legit method. Always allow the login in the present, and drop the old ones.
I would suggest keeping track of whether each user is logged in and allowing the second login to end the first login's session.
Then allow the user whose session has ended to report possible fraudulent activity if they were kicked off in error.
Don't try to do it by counting the number of IP addresses a user has an active session from - some users may be behind load balanced proxies.
The solution is to write your own session handler - probably easiest with a database back end - and only allow one user to have one open session.
You might want to tune the session garbage collection and inactivity. You should also ensure that your system is immune from session fixation attacks.
C.
In terms of security, and this is what you're getting at, it is always a good idea to store session data in a database anyhow. Particularly if you're on a shared server.
In terms of which user to allow and which to knock off that is a matter for you to judge. I suppose you could have some secondary form of identification to make sure they are the real owner of the account. The one who actually signed up to it.
I've done this before in a web application that had the same requirement. Here's what I did:
When someone logs in, you generate a GUID and store it in your database, attached to the user. You also store this same GUID in a session cookie.
Every time a logged in user hits any page on your site, you check their cookie GUID and compare it with the GUID that is assigned to them in your database. If these GUIDs don't match, they've logged in on another machine, and you log them out from that session.
This method works really well.