I've created a webservice, on which users can log in sending an oauth token. As response, this webservice returns a PHPSESSID cookie to keep the user logged in.
However, if you do log in several times, a new ID is generated each time. Examples:
ts1i3plmdcnmoivai637a27oe1
bhn1snms8kajmpo8ape5e5ctj3
d5467idr1ree9dcq6h9cqt9oj2
en2vbo1r62fqmrriid8l4rkvd3
All those 4 ID's are valid.
Is there any way make this sessid unique per user? So for example, when ID#4 is generated, previous 3 are discarded. Then I could handle a 403 error or whatever.
On the other hand, a second question:
Is it possible to make this PHPSESSID token longer?
If you want that then it's better to use your own cookies instead of php sessions.
You'll need to generate a random cookie key when someone log in, I'll call that random cookie key as cookie_id.
Then you need to store it in the database with the user_id it's connected to, so you can make a new table in database called sessions, with cookie_id and user_id fields (user_id needs to be unique), or you can extend your user table with cookies_id field.
After saving the cookie_id value with it's related user in db, you'll give that cookie_id to that user through cookies.
You can verify logged-in user with his cookie_id.
When logging out cookie_id will be null in db.
When another login happen, new cookie_id will be written over the old cookie_id in db.
That's it
Also You can set the period of your cookie with the expire parameter: http://php.net/manual/en/function.setcookie.php
For more security you can make cronjobs to delete cookie ids from db after some period of time. (You'll need to store the login date to do so)
Related
I know this is a recursive question, but, I haven't found a new solution, or a solution based on the new frontend frameworks or technologies.
I've a Vue + PHP application that users can olny log once per time. My current solution to block concurrent access is making a call to a PHP page with Ajax from 5 to 5 minutes storing the time. I store a flag in DB too, whether it has been registered or not. So, when the user try to log in, I check if the time is greater than 6 minutes or the flag is set to 0.
I think this is not the best way to do this. When the application has too many users it can cause too much load on the server.
There is a way to do like Netflix? An warn when triyng to connect and was logged in another machine.
If your end goal is to have it so that any given account can only be logged into one machine at a time, generate a unique ID at login and write that ID to the database for that user. Set that ID as a cookie for the user. When you receive traffic from that user, only consider them logged in if their cookie matches the value in the database.
When the user logs in to a new device, a new unique ID is generated and sent as a cookie to that new device. The new device's traffic has a cookie that matches the database, and is therefore considered logged in. When the old device visits your application, the login cookie no longer matches the value in the database, so that user is considered logged out.
When the old device logs in again, a new unique ID is generated in the database and sent as a cookie to that device. They are now logged in, because their cookie matches. The second device, having its cookie no longer match the database, is logged out.
This solution doesn't require you to access the database on every page, reducing database load significantly.
Add a field for sessionID to your user table in the database.
Set the default session handler before calling session_start() (needed for the next line of code to work):
session_set_save_handler(new \SessionHandler());
On every successful login, retrieve the stored $sessionID from the database. Destroy the old session with:
(new \SessionHandler())->destroy($sessionID);
Get the new session ID with:
$sessionID = session_id();
Store the new session ID to the database.
I am looking at the possibilty to set up a option to keep users logged in. Now I understand a session could be used to allow a user to navigate around without re-entering login information on each page only until the browser is closed and the session is lost. A cookie would be stored client side and has a duration until it expires or the user deletes the cookie.
I was thinking that I could use a combination of both
Create a db table (id,user_id,cookie_token,is_active)
User logs in which creates a row in the db table connecting the user to the cookie_token which is stored on the client browser (system) as well.
Each time a token is created, check to see if the user the token is being created for has any active tokens in the system already and set those to inactive before a new one is created.
Only one token can be active per user
So every time the user visits the site, the system looks up that token and checks is_active fields,
If the user_token is found and is_active = 1 or true, the user data is retrieved (id,name,etc) and this then creates the session and the session variables.
I am not able to find any questions or answers that use a combination of both so it could be that this is just overkill or a very bad idea, I just started to read up on sessions and cookies and have been trying to figure out a system that I could implement myself so would be nice to know if this is good or bad.
I can't reply as a comment anymore, because my reply would be too long...
I've implemented something like follows. Unfortunately I can't remember it precisely, but it would give you a pretty good idea:
Visit before manual login:
Start a session.
At successful login, store a user identification into this session and store a token value into the dB and into the cookie.
Next time the browser visits the page:
(re)Start the session.
Check if a user identification is set in this session.
If so, auto-login the user which matches the identification.
If not (session expired due time restriction or browser close), check if a token value is stored in the cookie and if this value matches a token value stored in the dB.
If an (unexpired) match found, auto-login the user and remove old tokens.
If the user identification is invalid and the token value is invalid/expired:
logout the user (which contains all actions to go back to "public" mode like destroying the session, removing tokens, cookies, etc.).
I'm searching for a solution to allow a user to be logged in only once at the same time. I'm new to Laravel and in this case I'm using it nearly out of the box (file session driver and default auth-handling with custom views).
My idea is to 'reset' the auth for a user after he logs in a second time, to automatically make all other active sessions invalid.
So my primary question is: Is there a way to accomplish this with some Laravel magic or do I need to invent this feature myself?
What you also could do is the following:
In your usertable, add one column:
sessionID (varchar or text)
Now what you want to do here is the following:
When a user logs in, store the ID of the session in the sessionID field. Everytime the user loads a page, or makes a request, check if the sessionID value in the DB is the same as the sessionID of the user that is logged in. If it isn't, kill the session and make him login again.
Now, when a user logs in, check the usertable if the sessionID value is already filled. If so, change it to the new sessionID. The result will be that all requests with the old sessionID will be invalid (because of your check) and the user can only access your webapp/website with the new session.
Thus this makes sure that your user is authed uniquely.
Currently, I have it set up such that, when a user logs into their account, it checks the cookies table in the database. If a row already exists in the database for that user, it updates the database and the user's cookie with a new hash. If a row doesn't exist for that user, it sets a new hash in the database as well as sets the cookie for the user.
The issue with this is that, if the user logs in from a different device, it will log them out on any other devices as the hash in the cookies won't match for the other devices.
How can I solve this issue? Would it be better to just, rather than update the hash in the database, keep adding new rows for each time they log in?
Please help.
if user already exists in database - do not update hash, just use hash from db to set cookie for new user
I'd add new rows for each time they login. Record the timestamp of when they logged in then you can check and remove any expired cookies so you don't have a ton of rows with expired cookie information hanging around. I'd perform this check every time the user logs in.
You also might want to consider storing the IP and/or user agent. Then you could setup a page to display to the user their current sessions and give them the option to revoke them if they want.
Please help start in the right way . I want to add 'if user is online' system. Which I will use to prevent multiple logins under 1 name, also this system will add option to users showing them who is online at the moment.
I understand that I need mysql table where I will store online users. But how can I understand each second if user is still here? if he logs out then ok, it's easy, but if he will restart? or something else ? So how can I controll all users and understand per second their status ?
UPDATE After some discussions with Cupcake I decided to have only who's online feature, letting 1 user to log in multiple times, cause it's difficult to prevent him from doing that in a comfortable way.
renew this table record each time user requests a page, updating access time field.
delete from this table all records which access time field is older than some reasonable timeout like 5 min
to prevent multiple logins under 1 name you have to store session id in the users table.
when user logins, stire current session id in this field
every time user requests a page, compare this id against actual session id, and make user relogin
What you could do, which is what I sometimes do, is this, in the user table have a column named session_hash or something similar.
And each time the user logs in, generate a new session hash yourself or use the session_id PHP has, as long as you use session_start on each page.
Then to retrieve the users row from the database, have a cookie with that session_hash.
Example
Login form
Username: [ ]
Password: [ ]
Remember?: [*]
[ Login ]
PHP page does the following
User logs in ->
System generates a session_id or "salt"
Updates the users row with the session_id or "salt" value
Check if the value of the "remember" checkbox is true ->
Sets a cookie with that session_id or "salt" with a month or so expiration date
Otherwise just create a normal cookie with the value
Then on each page do the following
Check if the session_id or "salt" cookie is set ->
If it is, fetch the users row from the database
SELECT * FROM users WHERE session_id/"salt" = value of cookie
What all this does if lets the user choose if they want to be remembered each visit, if they do create a cookie that doesn't expire for at least a month that way they will be remembered next time they come to the site, but if they login from another browser or computer the "salt" won't be valid on the other computer.
Simply invalidate all old sessions of the user, once he opens a new one. In that way, he can only run one session (aka one login) at a time.