I just built a simple login system that uses sessions. When the script verifies that the username and password are both correct, it sets $_SESSION[username] and $_SESSION[role], and then on every page of the site it just checks whether these 2 session variables are set.
Considering that the server handles the sessions, this should be a secure solution, right? Or should I set $_SESSION[md5(password)] as well when logging in, and then check on each page of the site whether all session variables match the user data in the database?
Storing the password in your session is a bad idea, it also doesn't add any security to your website, since sessions are managed by the server.
You are however still vulnerable for session hijacking. Take a look at this question to learn more about how to prevent it.
Don't store passwords outside your database. Don't even return passwords from your database. All you should need to get for session storage is the userID. store that in the session and use it to lookup role level and name data when required. If you are concerned about someone hacking the session data and changing the userID number then you can store a hash of the userID number in the session aswell (I recommend using something a bit more secure than a simple md5 though, there are plenty of rainbow tables around for that nowadays) and compare the hash in the session to the hash of the userID at lookup and verify nothing untoward has been happening.
Related
I'm trying to roll my own authentication system in codeigniter, and have stumbled onto a couple of roadblocks.
If I have the sessions set to use a database, is userdata stored in the database alone or in the cookie as well? I'd like to store the hashed password in it to verify each page load that a user is actually logged in with the correct pass, and I do not want the hash to be accessible clientside at all.
How can I prevent sessions from being stolen? I've enabled IP and hostname verification, is that stuff automatic or do I have to perform the checks myself? Will that be enough to stop people from stealing session data?
Userdata can be stored in the Session. If you have sessions setup to use a database, the only cookie will be a ci_session cookie or whatever you specify, and the cookie + ip/hostname will be matched to the database sessions table.
Storing the hashed password in-session will be completely safe, its in your own database. No problems.
Preventing sessions to be stolen should use a ip or hostname match (either every page load or a little less often, some people have dynamic IPs), not sure about automatic verification, but it's always nice if you check by yourself.
Preventing session data stealing is pretty much like that. Unless someone intercepts your cookie, and magically reports a false IP (or, well, shares an IP/hostname with the target), it's enough. You could also do another check, match the user_agent. That you'll have to do manually.
That's pretty much everything.
I'm setting up a user account system on my web site. The SO consensus seem to be reflected in this SO question/article. It recommends this approach by Charles Miller to store the username and a large random number 1) in a cookie and 2) in a separate table in the DB. The user can be reauthenticated in each subsequent session by querying this table using the cookie (if it exists). If a match is found, then a new $_SESSION is set for that session. It supports simultaneous logins from different computers.
My question...
Prior to reading security questions on SO, I was thinking about storing user information in a way similar to the way vBulletin does it. As I understand it, they store the user id and the hashed password in separate cookies on the user's browser.
After the user logs in, they use a $_SESSION variable (e.g. something like $_SESSION['user_hash']) to maintain the authentication for each page request. I don't have access to vBulletin software, but I assume that $_SESSION['user_hash'] is maintained in a separate MySQL table along with another piece of identifying information - e.g. user id/password hash/other - in order to enable logins from different computers.
I was thinking about creating the hash by doing this:
$_SESSION['user_hash'] = $random_hash = sha1(uniqid(rand(), true));
For future sessions, if $_SESSION['user_hash'] does not exist, then those two cookies can be used to auto-login this person for a new session. I would plan on implementing the $_SESSION security measures outlined in this SO question .
Is the vBulletin approach acceptable from a security standpoint? If storing the user id and the hashed password in a cookie is problematic, would encrypting them alleviate some security concerns? Or could something else be done to secure the cookies?
Thanks for any suggestions.
The problem with this approach is that there is far more potential for session hijacking than with a standard session cookie. If I were to steal that cookie, I would potentially be able to access the user's account for as long as they don't change their password. If session authentication uses a session ID that's unique to the session, it's easy enough to set the sessions to time out after a period of inactivity by storing the last activity time in the database.
Another thing is that I would argue you are overcomplicating your own code. You're already using PHP's sessions, which I've always found to work very well, so why not just store the PHP session ID and a link to the user record in the database in your user sessions table? What more do you gain from setting another cookie with your own hash in it? That's why PHP is such a nice language to use because a lot of these high level functions, such has session handling, are already done for you
I'm creating a login system in PHP, and I want to know how to best protect the user information string in my cookie. I was thinking of encrypting the string with a key somehow? Is this the best way? I'm kinda new to this.
Thanks in advance.
Don't store sensitive information in cookies. Store a session ID hash to connect the logged in user with their account.
Aaron Harun has the right answer for you. There's basically no need to encrypt such data as long as you store it in a session, because that data never reaches the client/browser/user, as it is all server-side. When you create a session on PHP, it handles the cookie stuff for you, so you don't have to worry about that. In most cases, there is no need to deal with cookies. In security, dealing with cookies is detrimental.
I've seen some sloppy sites that actually store the username in a hidden field on a form, which allows anybody to simply edit their local copy of that form and take actions as whichever user they like. This seems like an obvious problem, but cookies are no better.
If you truly think it's a good idea to design a homebrew authentication system, you need to design the database first. Don't store plaintext passwords, store a hash instead (like md5, sha-1, etc) and at that point there's no harm in generating a salt for each password (a random string that you append to the user's password before hashing it, and store that salt with the password hash because you'll need it later--this prevents dictionary hash attacks, ie rainbow tables).
You should never store secure information in a cookie. Cookies are saved in textformat on the user computer, and there are many reason why you should never stock sensitive informations in them :
Cookies are basically text files, which can be opened by anyone on the computer, with any text editor.
The cookies are stored on the user computer, this mean he have no time limit, no connection limit, no processing limit, so he can try to brute force any data as much as he want without being worried of getting ip banned/kicked...
You should only stock things like a username to remember or a session id.
If you absolutely MUST store information in a cookie instead of the user's session, consider signing it with HMAC. The hash_hmac function is a builtin in modern PHP versions.
If you're storing a user login for a "remember me" feature, store both the user's ID and a hash of information that is only available in your database. For example, hashing together the login name and password and storing that with the user's ID in the cookie is reasonably secure. If the user ever changes their password, all the machines he's logged in to with that method would be invalidated, and there's no way to simply change the ID in the cookie and still get logged in, because the username/password hash won't match.
You get sessions for free! That is data stored server side, automatically handled by PHP/framework-of-your-choice. You just put data into the session, which is associated with a random UID stored in clients' sessions. On the clients' side, this is the session cookie. This ID is automatically generated, you can fine grain the behavior manually.
Data stored client side is never safe, no real encryption available. Sessions you will need anyhow for keep track of logged in users. If you have lots of data, you can use the ID to identify associated data from other datastores (DB, XML etc.)
My question is about creating a secure log in routine. After comparing the user name and password to the stored values I set a session variable called logged to true. Then as the user surfs around the web page I just check the logged variable for true or false to determine if the user should have access.
This is my first time creating something like this. Is this secure? I feel like there is something else that I should be doing to make sure that users are valid.
Anyone that gets your session cookie, is able to login as you. If you bind a session to an ip address, it's a lot harder. But this can give you problems with people that have changing ip addresses. It's up to you to decide if that's worth the trouble.
If you're not handling any kind of sensitive information and just trying to provide a personal user experience, what you're doing is fine. However, if you're truly concerned about security, there are several other approaches you can take. The first is to create a database table called "user_tokens" or something similar. When a user signs in, create a random key and store their ip address in the table associated with the key. Also, store that key in a cookie on the clients' machine. Anytime they try to do something sensitive, you can compare their ip address and key of the cookie to that of the database.
Research a little bit into Cross-Site-Scripting (XSS) and session hijacking. The method I've outlined above will really cut down on this.
Sure, it's secure but there are precautions you should take to prevent insecure circumstances/attacks.
There is nothing wrong with the mechanism you've described, at all. But the implementation is incomplete/unspecific. You have to consider password storage, and the procedures you'll use for login.
In response to a complaint, here's some issues OWASP brings up about authentication/sessions.
1. Are credentials always protected when stored using hashing or encryption?.
Yes, store your users passwords as salted hashes.
2. Can credentials be guessed or overwritten through weak account management functions (e.g., account creation, change password, recover password, weak session IDs)?
No, those functions should be protected by a security question/email link.
3. Are session IDs exposed in the URL (e.g., URL rewriting)?
Nope, they shouldn't be.
4. Are session IDs vulnerable to session fixation attacks?
Nope, don't allow users to set their session id through any means besides login.
5. Do session IDs timeout and can users log out?
In cases where the user hasn't otherwise specified "to stay logged in for two weeks", sessions should expire soonish.
6. Are session IDs rotated after successful login?
Yes, using session_destroy() and session_start() will accomplish this.
7. Are passwords, session IDs, and other credentials sent only over TLS connections?
Sure.
Ultimately, you have to consider the kind of data you'll be handling. Never allow someone to gain access to a user's password, since it could compromise their data elsewhere. But, if you're running colorakitten.com, don't loose sleep over the possibility of hijacked sessions: "Oh no, someone hacked my account and discolored my kittens."
Read: PHP Session Security
You are probably going to want to store the username in session as well in order to properly customize any pages for the user. What you described is "secure" but the security of your application is hard to assess without knowing what else you are doing.
I want to make a login system using cookies/sessions but I'm not sure what security and such is like with them.
With sessions, if "login" is set to "yes", can I trust that? Are users able to change what it returns? Should I just store the encrypted password and check it on every page?
With cookies, would I have to check for things like mysql injections?
This might sound like beginner stuff, but it would really help if someone could clarify it for me. Thanks in advance for any replies!
If you set a session variable, the user can't directly change it unless they hijack another session cookie.
What you mainly have to watch out for is on shared hosting, your session data isn't secure (typically other sites can see it).
It's also worth noting that cookie data isn't secure either. It shouldn't be relied upon in the same way that form data shouldn't be relied upon (no matter what client validation tells you).
Your best practices with passwords are:
Store the password in the database in a hashed form, preferably SHA1 (first choice) or MD5 (second choice);
When you receive the user's password, encrypt it and check it against what's stored in the database;
Set the logged in username in the user session;
Expire the cookie after some period (even if its days) rather than having it last forever; and
Use a secure connection (HTTPS not HTTP) where possible. SSL certificates are cheap.
As several people here have stated, do not trust user input - ever. By sanitizing your input, especially username & password fields you help to ward off SQL Injection attacks.
For all that is good & holy don't store usernames or passwords in cookies, they're sent back & forth to the server on every request and anyone watching the stream can snatch that data...then you're in big trouble.
Here's a couple articles you should read on sessions, security and hashing - just hashing your passwords to SHA1 or MD5 isn't enough, salt them so they're even more robust. There's no such thing as impenetrable security - even if you do EVERYTHING right someone can break it - it's inevitable. Your job is to make things as hard to break/exploit as possible.
The more work involved in breaking into your site, the more valuable your content has to be to be worth the effort. Your job is to discourage malicious users.
This article has some nice info on creating unique fingerprints for your visitors, helps to make session hijacking more difficult - PHP Security Guide: Sessions
This article deals with basic password hashing & salting techniques - Password Hashing
This is by no means an end all & be all - you can make a career doing security and the like, but they're a good starting point. Someone here can probably point to better / more advanced articles, but I've personally found these helpful in shoring up my code.
Rule of thumb: do not trust user input. Cookies are user input, session ids that are stored in cookies are user input, http headers are user input -- these things must be triple checked for every possible thing. Session data, on the other hand, is stored on your server, so it is more or less secure if not stored in /tmp.
One of the most popular setups for session authorization is this: session id is stored in cookie, and everything else including password is stored in session. After starting a session based on id from a cookie, you should get user id from session data and then check if password stored there is still valid.
A good practice to use is to have 3 variables stored. One for if they are logged in, one for their username and one for a randomly generated hash (that is generated when they login and stored in a database along with the other user info). This way, if they change their username that may be stored in their cookies, it won't match the one that was generated for that user when they logged in.
Example: Cookie data could be:
logged_in = true;
user = 'admin';
sessionid = [randomly generated id (I usually just md5 a randomly generated word that I create)]
Everytime they login, a new sessionid is generated and stored in the database in it's own field. Now if I were to change my cookie information and change the user variable to say 'user' (which would be another user they may be trying to hi-jack). The sessionid would no longer match up to the one for the second user and the login would be denied.
Here is a quick example I stole from a CI project I worked on a couple weeks ago:
function logged(){
$logged_in = $this->session->userdata('logged_in');
if($logged_in){
$userid = $this->session->userdata('userid');
$sessionhash = $this->session->userdata('hash');
$this->db->where('id', $userid);
$this->db->where('hash', $sessionhash);
$query = $this->db->get('members');
if($query->num_rows == 1){
return TRUE;
}else{
return FALSE;
}
}
}
Any and all user input needs to be scrutinized and sanitized religiously, be it GET and POST data, cookie data..
To answer your question if storing the login state in a session var is safe, the answer is yes. Just remember to sanitize everything the user sends you, no matter how safe it is supposed to be.
This login system is a great one to learn from.