I am making a registration/login system with php. I think I have all the initial login stuff worked out(hashing password with salt, store in db...).
My question is in regard to keeping a user logged in between pages after their initial login. The way I understand it is that one method is to have a table of sessions on your server that stores a random unique id for each user and to store that id in a cookie on the user's computer. This way for each page they load all you do is lookup their session id in your database.
What I don't understand is how is that is secure? Couldn't somebody just sniff the ID and then fake being that user. Someone could even just try guess IDs.
I also read that it is better if the ID changes on each page visit. How does this increase security? It seems it just would decrease the amount of time any ID could be used.
Also how would any of this change with a "Remember Me" feature that would be stored for long time?
The ID you are describing is precisely what the session ID is, except it's handled for you transparently by php (browsers pass along this session ID with the cookie).
The security flaw you are describing is precisely what firesheep takes advantage of. You can prevent the session ID from being sniffed by making sure that all authenticated requests to your site take place over ssl. This not only includes logging in, it also includes any time an authenticated user tries to access a page (which means the browser will be passing along an authenticated session id).
If a user tries to access a page not via SSL, you should ideally redirect them to an SSL page and give them a new session ID, because the old one could have been compromised.
The key to such a system is that you don't randomly generate the key--you generate it using facts about the user, ones that another client wouldn't have knowledge of--like the user's IP address, user-agent, and session id. Then you make the user authenticate using that key and their session id (which is transparently handled by PHP).
Related
Since php login application uses session id(one for each user) which is stored in cookie which is send as header information to server that allows the user to get automatically logged in(assuming that the user is already logged in some another tab in same browser lets say Chrome).
My question is if I store that user session id cookie information in another browser(lets say Firefox) and open the same application, will the user will get automatically logged in or not.
Or if someone finds out my session id and store them in its browser will the application will allow the user to login or not.
Take a look at session hijacking.
If somebody steals your session cookie, and you are still logged into the website, then yes. The attacker can log in using that session cookie.
And because of the answer given by #JonTan, you may see the fact that auto-login based only on PHP's session ID is not secure.
There all sort of solutions to that problem, but the base of each of them is to try and identify as many "unique" attributes of the user.
For example, store the user user-agent and ip address. When you "auto-login" the user, check for those details as well, and if they don't match than destroy the session. You may also add another token that you generate from this data as an "extra" security attribute and store it in the cookie, and check if that token match as well (you will most likely want to generate this token based on the user-agent, ip etc, so that you will be able to regnerate the token to match).
When a user logs into my site it creates 2 cookies, one with a session ID (that relates to the user ID on the backend) and a remember me cookie that lasts for 3 months.
The remember me cookie is constructed as:
userid:timeout:hash
Where the hash is a HMAC SHA256 hash of userid:timeout to prevent tampering.
If the session ID does not exist (user closes their browser and opens it again so the cookie is gone, or the session ID does not exist in memcached) it looks at the remember cookie and re-generates a new session cookie, providing it has not timed out and the hash is correct.
However I don't see the point of having a session cookie at all, as the session ID just points to a user ID in the backend. I can use the remember me cookie instead to retrieve the current user.
So I am thinking of scrapping the session cookie completely, and would be interested in hearing some thoughts on this. Does this approach sound relatively secure? Could I make it any better?
Thanks in advance!
Yes, it is indeed secure enough for most cases, but why including user specific data in the cookie when you can avoid it? Also, there's a small disadvantage with this:
What happens if an user manages to steal a cookie from another user, you'd have to change the whole way the cookies are generated or that user will always have access, therefore resetting everyone's cookies. Imagine now that it's your cookie that gets stolen...
This is my solution for that: create another row in the user table called 'userhash'. When an user logs in, you generate a random hash without taking any of his input, just random, and store it both in the table and in the cookie. Then you only have to store userhash:timeout in the cookie. You check that against the database to see if it exists, if it does, that's your user. When the user logs out, the cookie and the row in the database gets deleted. For obvious reasons, you'd have to check that the cookie exists before comparing (there will be many empty).
Note: This method would only allow one registered cookie at once, so no laptop + desktop. This is good, since stealing is made more difficult as it only lasts as long as the real user doesn't log in, and bad because it only allows 1 computer. But you see the idea and how you could use this method but having several computers logged in... facebook-like.
PD, it'd be nice if you said how secure your app must be actually...
PD2, in case you haven't think about it yet, there are other more serious security concerns (SSL to say one).
I've been researching the best (and safest) ways to implement persistent logins on my website, and I've come up with the following:
When a user logs in, a cookie is created containing the user's ID/username, and a randomly generated number (token). The token is stored in a relational table along with the user ID/username. Every time a members-only page is loaded, this cookie is checked against the relational table, and if it exists and matches with the token, the login is valid and the page can load. If not, however, then the login is invalid, the cookie is destroyed, and the user is prompted to log in.
I was thinking... to save on database access every single time a page is loaded, I could also have a session variable that lasts, say, 10 minutes, and is destroyed automatically when the browser closes. If the session is alive, then it's refreshed and the user can proceed. If the session expires, but the cookie is still valid, check the cookie, reset the token, store that new token in the database (while eliminating the old token, or storing it in an archives table for future reference), and reset the cookie using the new token value.
However, what would the session contain? And how could the session not simply be faked with some JavaScript? Perhaps the session contains a one-way encrypted hash? What would be used to generate that hash (user ID, etc.)?
I'm kind of stuck on where to go from here. I get the cookie stuff, but using temporary sessions (to avoid repeated calls to the database every single time a page is loaded) eludes me. Any help? Thanks.
Cookies should be fine (an alternative would be to store it in the HTTP header), however I don't see the need to store the username/ID in the cookie. The token itself should be enough. You can use a UUID as a token. Store that along with the username and a last_access_timestamp in the database table. And only send the token (in a cookie or in the HTTP request header) on every request. That's enough for implementing sessions in my opinion.
A token is generated on a successful login of a user, stored in the database and passed to the user. Whenever a user accesses the webpage, the token is passen in the request and is validated. If valid the last_acces_timestamp is refreshed and the user can proceed. The lookup in the validation will be done by token and with the username you can do the authentication and authorizaton. If token is invalid or expired, forward the user to a login page.
Deleting expired sessions out of the db can be done periodically using a cron job or on creation of a new session.
For performance reason you might think about storing the session in a hashmap in memory. Since it might be costly to always update the database.
Also think about using HTTPS, to prevent people sniffing the token.
I have solved this the following way, few months ago:
https://stackoverflow.com/questions/12829994/java-custom-session-implementation-expired-sessions
Usage of UUID is not recommended according to RFC 4122 it is stated that
Do not assume that UUIDs are hard to guess; they should not be used as
security capabilities.
I would recommend combining and multiply all of the following information together into a hash with also encrypting it using a public key stored in your server.
UserId (Or User UUID that was generated for each user while registration)
Encrypted His/her password (considered as a private key for encryption per each user)
Time stamp
Client Operating System
Client User Agent (Browser name)
For storing tokens, you could use either memcache which is used heavily in big companies or redis if you are focusing on persistence.
Keep sure that your cookies have the following attributes, for more info about Cookies
HTTP Only cookie
Secure Cookie
I've created a login system that uses cookies and stores a session ID in a database, so your login will only work with that particular session ID. I realise this has a few problems:
If you login on another device the session ID changes (no multi logins)
The session ID is really the only thing identifying the user as logged in (I'm not really sure if this is a security risk since the cookie is domain specific)
However I want to retain the persistant login that comes with cookies while still keeping stuff secure.
Effectively I want to know if there is a better way to securely log a user into a website using cookies.
First of all, keeping stuff secure and persistent logins don't go together; you will always compromise security by introducing persistent logins in some way.
Having said that, an article from Charles Miller outlines such a system:
create a (big enough) random key, preferably by using /dev/urandom or openssl_random_pseudo_bytes() and associate it with an account (in database terms: a separate table with the random key as the primary (or unique) index and the account as a foreign key); the key will be the cookie value.
when a non-logged in user presents a cookie, the key and account are looked up and the user is logged in; afterwards, the used key is replaced with a new random key (cookie is updated too).
users who are logged in via cookie alone should be asked for their password again when they access sensitive (account) information.
the user should have an option to log out from all his devices.
It's also a good practice to use a renew the session id using session_regenerate_id() whenever a user is logged in (either via a form or cookie). This prevents someone from launching a session fixation attack against someone else and possibly steal their identity.
An improvement on this design by Barry Jaspen that can also handle identify theft detection can be found here.
I'm developing a web application using Codeigniter. When a user authenticates with my site I'm currently storing their 'user-identifier' in my session cookie (which I have enabled encryption on). Several of my model classes use the value in 'user-identifier' parameter of the session/cookie to make changes to properties of user accounts.
My concern is that I'm wondering if it's possible for someone to take a valid codeigniter-session cookie with a user-identifier that I've set, change the user-identifier's value to the value of a different user, and make changes to another user's account. Would codeigniter/php sessions create an error if someone attempted to change a property of a session cookie?
Open your /application/config/config.php, locate "sess_use_database" and change it to "TRUE" if you haven't already. This way all session variables will be stored in a database table and session cookie will only contain session id string.
For added security, you can also change "sess_match_ip" to TRUE. This way if someone steals your user's cookie and tries to pass it as their own, session will be destroyed.
"if
it's possible to take a
valid codeigniter-session cookie
change the user-identifier's value to
the value of a different user, and
make changes to another user's
account."
My answer is not really CI related, so please bear that in mind.
When you auth the user "username1" what should be sent back to the client, for auth purposes, should be a hash that the server correlates to that user. All communication between the client and the server will rely on that hash.
The server will generate a unique hash per user and the hash should have a short time to live. Can someone capture a hash and pass as that user? Certainly. That's why you should also check for the user's Agent and IP to check if they match the hash in order to prevent session hijacking.
NEVER DO THIS:
If seen some new developers storing the username in a cookie and reliing on that client sent variable to update their databases. Never do this. Do not ever, ever trust the client. When the server gets the client's hash it should check if it belongs to an authenticated user and grab the user_id (variable to update the user data) from the server. NEVER from the client.
I'm not sure what your "user identifier" is exactly. The general rule is, don't store anything in the session cookie but the session ID. Store everything else (like a user ID) internally on server side, and retrieve it using the session ID.
If the user changes the session ID (which is a random string), a new session will start. The idea behind the session ID is that it's impossible to guess other user's IDs - that's why it's random, and so long.