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.
Related
I am making some login system just for learning. The idea is that a user creates a account and enters informations like name, phone no etc a unique Id is given to each record, a session token which is a hash of phone no and current time is also stored. When the program verifies phone no and password during login it sets the session id as cookie and fetches information based on the session id which is unique index.
A new session id is given every time when the when the user log outs.
The leak is that anyone can copy the value of session id cookie and send a request to the server with that cookie data and can find the information. How can I make this secure?
Kindly give some suggestions.
The leak is that anyone can copy the value of session id cookie and send a request to the server with that cookie data and can find the information.
This is not a leak. If someone can get other's cookie data, they may as well install a keylogger on their computer to steal the password. If you use HTTPS and generate a completely random session id instead of the method you mentioned, then everything is very secured and you need not worry about it.
Edit: You should also add secure to your cookie as you don't want to ever use HTTP when talking about security.
After logined user, I keep user ID inside cookie ($_COOKIE['user_id']) and after this mysql check if isset user_id inside cookie and if user_id is exists in DB:
SELECT * FROM users WEHERE user_id = '$_COOKIE[user_id]'
It works, but cookie value can be changed by every cliend, so client can set cookie user_id to 1 or 2,3,4 and it will be loggined, So they can hack page.
I want to hash or secure somehow my cookie user_id value. I hope you understand me.
Can you give me any suggestions?
Do not do that in a cookie. Save a hash in the cookie and store the corresponding user id in your database. You can't make the cookie secure.
To be more clear:
When the user logs in, store a unique hash for him in the database. This could be something like that: sha512('9a7fd98asf'.time().$username). This is the value you save in the cookie, too. You know the user is logged in, if he has such a token in the database and if it matches the value from the cookie. This actually is how sessions are handled.
Cookies are prone to numerous types of attacks including someone stealing a cookie from one user and presenting it later to impersonate that user. If you were to instead use sessions, you would either have to use session cookies or URL, both of which are problematic from a security point of view.
The best you could possibly do is encrypt the cookie so you can later decrypt it when you read the user_id. This will ensure that a user cannot randomly change their user_id. However, this does not protect against one user using the data from the cookie of another user.
To guard both against reply attacks (either by the same user, or by a different user), in addition to storing the user_id, you would also want to store the expiry time in the cookie. When you get back the cookie, you can decrypt and also get the time that you need. This does mean though that this type of replay attack is possible within that time during which cookie is valid.
For encryption/decryption, you can search and find how to correctly do it using the language you are employing. You will still have to test against corrupted cookies (in which case you can assume user is not authenticated).
You want to use a meaningless token. That's the most secure way, because the token is inherently meaningless and cannot be attacked in itself. Because the token also needs to be stored on the server with associated data, this also gives the server the ultimate control over logins; because the server can revoke active tokens at any time (you cannot revoke a cookie which stores just a self-contained user id).
A standard PHP session is such a meaningless token and works just fine for most cases. Sessions can even be configured to last extremely long, and you can even change the session storage backend to a database or any custom backend you want.
If, for whatever reason, you need something else, you still want the same idea:
generate a completely random, meaningless value
store it in a database, together with what user it belongs to
send the token in a cookie to the client
You could store an additional cookie, named 'user_hash':
$_COOKIE['user_hash']=sha1($user_id . md5($user_pass . $salt1) . $salt2);
Using some constant $salt values.
When using the user_id cookie, first check if user_hash matches the user login information stored in the database.
Since the sha1 is irreversible, the password cannot be derived from it.
This is how I'm building a login system:
Login:
Check username and password supplied by user with the database.
If username and password is correct, store only user ID in session, something like:
$_SESSION['userid']=$userid;
If User has checked the option to stay logged in, then set 2 cookies, 1 with userID and other hashed string.
To check if user is logged in:
Check if Session exists, the user is logged. is it ok?
If session does not exist, check if both cookies, userID and hashed string exist.
If Both cookies exist, validate them.
As the Session is stored in the server, is it secure to store only userID ? Can a user pretend to be other user and store his userID in the session and log in as him?
Thanks.
Yes, this method is very insecure. I can sniff traffic, intercept your cookies, and your system will accept me as an authenticated user. You are making the assumption that if you get a cookie with a userid and the hashed string, then that user is the same person that originally authenticated to create the cookie. That is a poor assumption, because cookies travel in plain text (unless you encrypt them), so as long as I can grab a cookie, I can pretend be whoever sent that cookie, and your system doesn't know any better.
Edit:
If you are going to use unencrypted cookies, why not just store the session_id in a database table? That way, at least someone that gets hold of a cookie won't have a valid username. Create a sessions table, and when someone successfully authenticates add a row with their user_id and the session_id. Each time a page is loaded, check to see if the session_id in the cookie matches a row in the sessions table. If yes, you can assume the associated user_id is the authenticated user. This approach is just as secure as the one you suggested (i.e. not very), but it's less complex and doesn't give away valid usernames.
Yes it's possible and very extended, this kind of attacks are called Session fixation and in your system (as David said) anyone who sniff your traffic, or have access to the user's drive and steal his cookies, may supplant a logged user.
The best protection is, of course, SSL, but if you can't use it in your website there are other things that can prevent (but not fully protect against) this attacks:
Save info about the user in the server-side when he login, good candidates for this are the IP and the user agent, but any other data that don't change in the entire session can be valid.
You can regenerate the session ID in every request, with this if the session ID is leaked the attacker must use it before the real user do any other request, but beware because every time the session ID is regenerated (in PHP at least) the user's session data is rewited, so this can be expensive if you have a lot of users or if you save many data of every user (this means that, if you're saving the session data in a file, the file will be deleted, created, and writed again).
Well, right now I can only think in these two, it's not much but at least you will put an extra complication to the attackers.
One more thing, don't trust the user's cookies, they can be changed by the user (or the attacker) at any time, treat it like any other user input.
PD.: Sorry for my horrible english, I'm truly trying to improve it ^_^
you could add an ip that the user id should belong to (in your database), that adds a little extra security - it might not always be the best solution
Yes it is ok to check if the session exists and also check that the user id is greater than zero.
The 'remember me' function is subject to sniffing as it's not over ssl, however that is how 'remember me' functionality is done.
Assuming this is happening via SSL, my biggest concern is your first step:
Check username and password supplied by user with the database.
You should be hashing passwords, and comparing the hash of the user-supplied password against the previously hashed password stored in your database.
You also don't have to worry about storing only the user ID in the session array; the session is stored server-side and is as secure as the rest of your server.
One potential problem is that everything is being stored in cookies. If someone somehow manages to get their hands on the Session ID, then they've also got the username and hashed string.
Chris Shiflett suggests creating some kind of fingerprint from the User-Agent string, or some other regular header, and storing it in a GET variable.
One way to bump up security is to have everything sent over SSL. Any time any kind of potential information is sent or received (such as the Session ID in a cookie), make it encrypted - not just the login form.
It is mostly correct but I don't agree with the cookie-option. This way if someone gets the two cookies can move them to a different computer and still use them.
The "remain logged in" function should be restricted to that computer. A possible solution is that if the user wishes to remain logged in you set the lifetime of the session to 1 week or so. Also you have to store the user's IP address, User-Agent and possibly X-FORWARDED-FOR header, and check them on every pageload against the stored values.
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.