I have a small internal website for a charity, it's were the staff login to access documents and rota. Although it's only meant for certain users it is on the web so it's public therefore I'm still thinking about security. I need your opinions on the following because I'm not very experienced.
I've always stored two cookies when the user logs in. The first is their user id and the second a cookie id so people can't just change the user id and be logged in the cookie id needs to match. It's compared to the database every page. The problem is the cookie id is just a random number it will take no time for a PC to cycle through a range of a few hundred thousand combinations to find the matching ID for each user. So how can I stop this? Would PHP's uniqid be good enough?
What other attacks should I consider, apart from SQL Injection (already prevented)
Thanks
Store the client IP of each session on the server.
If the client IP for a session changes, then that's suspicious.
Another thing would be to give sessions a lifetime.
Like, invalidate a session if nothing happened for an arbitrary amount of time.
Last but not least, do only store a random ID in the session database and map that to the user instead of storing the user-id directly into a cookie.
Related
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).
On Monday, I thought I had solved the session hijacking security issue by setting the session as the user IP, until I logged in. I had two users with the same IP (myself and a test user) and it kept switching between the two. Is there a way to prevent this and allow two users with the same IP register on my site?
Thanks in advance,
Terry.
You may have been reading advice about storing the user's IP in a table along with the session id (not in place of). You'd then check to make sure they're coming from the same IP on subsequent requests, otherwise, force them to login again. This method has problems as well a user's ip can change as often as every ten minutes depending on their ISP!
Use the session id provided by PHP as it's unique and difficult to guess. Require it to be read from a cookie and never from the URL.
SSL the entire site if it is a concern and apply a short cookie time out. The ssl will encrypt the cookie and transmission so it can not be sniffed off the wire. A short time to live will make the cookie useless soon after it has been taken from the "logged in" computer if they have direct access to the system. So in short get a security cert and go on as normal with a normal php session.
I take it you're looking for the user's information in the MySQL database, using their IP? That is wrong. The only way to be truely unique is with a primary key field.
Either store the primary key as the session and pull their data, or store relevant information in the session and only pull anything else when it is needed.
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).
So on my application login form I've got one of those little boxes like [_]remember me
When the user checks that we set $_COOKIE['rememberMe'] with the value of the username. Now when that user comes back 3 days later, I obviously want to recognize them and re-log them in automatically. It doesn't sound safe to simply check for the existence of that cookie and then use it's value as the username to login without a password. But I'm not sure how else I would log them automatically... Is there a way this usually done?
Your cookie should have three values:
1. username
2. expiration time
3. a session code
When a user logs in, generate a session code and set an expiration time.
Store that session code and expiration time in the cookie and on your database.
Then whenever user returns to the site, and if user is not logged in:
1. check for the cookie
2. check for the cookie against the database
If all three variable matches and the expiration time is not over, log the user in.
Alternatively, if you simply encode the session code as say a md5 of ($username.$expiration_time), then you won't have to set up a database for storing and checking. Although having a database with randomly generated session code is much safer.
This is extremely unsafe. Since the cookie is the only thing you have to go by and the cookie is transferable from system to system, you would be vulnerable to cookie poisoning attacks and cookie copying attacks. If this is indeed the course you're set on, you will need to use some manner of foot-printing the user's system and storing that information in a database somewhere possibly as part of a persistent session on a session state server. This information could then be compared with the new login so if the cookie is transferred to a different system, it will not match and the automatic login will fail. As for accomplishing the login, I would recommend at a minimum to have a session state database where session information could be stored per session ID and username. If these 2 items are stored in the cookie, this information could then be used to get the information out of the database, and the foot-printing could be used as a stop-gap (although a very weak one) to prevent misuse.
The only information you need to store in a cookie is some unique hash that's going to point to the right user session in your system. Storing username or other information is redundant and unsafe considering the fact that username can be captured by an attacker and used with a combination of other information. To make the system more safe, you should implement a layer that'd check user's location by the IP address and his browser details. I suggest you should learn from what companies like Facebook and Google do with user accounts.
Place a random and uniqe hash in the cookie and store it in DB too with the current client's IP address.
If the user comes back, you can search for the hash in your DB.
A feature that is currently missing from one of my web apps is that a single user can only be logged in on one machine at a time. That is, if the users logs in elsewhere, his previous session will be logged off.
This is due to my current users table having the columns:
user: id, username, hash, salt... cursession
When each user logs in, the session ID is put into the "cursession" field and on each page-load, is checked against the database. As a result, only one "session" can be active at a time.
Is the current table structure and method secure and standard? This system was pretty much improvised, and I have no professional experience.
What would be a way to allow multiple simultaneous logins? I'm simply thinking of adding a "sessions" table with more userid-cursession relations, but what's the standard method for doing this?
I propose that you put the current logged in userid in the user's session (as a session variable), and drop the cursession field from the table altogether. You don't need to reinvent session handling since PHP already has it built-in.
That way the user can be logged in at multiple computers at once. Session variables are safe too, since they're not manipulated by the browser. The only thing kept in the browser is a session id which identifies the current session, all other data is stored on the server-side. The only thing that will happen if the user changes his browser cookies is that he will be logged out (start an empty session), so he can't force himself to log in as someone else.