I have implemented a login class in PHP, and want to create a remember me type functionality so users won't have to login with each visit. I have researched this a bit and was preparing to write it using PHP setcookie(...) but then ran across this page: How to Create 'Remember Me' using jquery , store cookies. I was planning on writing this in PHP since it's my strength, but this page makes it look so easy in js: http://www.quirksmode.org/js/cookies.html
I am looking for a little guidance on gotchas for each method, and more specifically issues related to security. I just want to make sure I don't complicate the task or open any holes by providing this type of functionality.
Thanks, Kris
OpenID, facebook connect, twitter signin
I would advice you not to right(read below for cookie rememberme information) your own login system, because coding a secure system is difficult(storing password secure is HARD). It also saves you a bunch of coding. For example when you sign in at my openid example using google you can tell Google to remember you for 30 days. The code used for my example can be found at my github page.
Http_only
You should use http-only cookies to protect yourself against cookie stealing(Try not to use cookies from javascript). The php function setcookie also has a http-only flag. For session you could achieve this using something like:
<?php
ini_set("session.cookie_httponly", 1);
// or
session_set_cookie_params(0, NULL, NULL, NULL, TRUE);
?>
Do not Store data inside cookie
Also you should store as little information possible inside the cookies. Get the data from database(session). I think you easily accomplish rememberme cookies setting the expire of your sessions as high as you like, but not to high if you ask me.
Interesting read
This is also a pretty interesting read to improve session security: http://web.archive.org/web/20120417214604/http://segfaultlabs.com/files/pdf/php-session-security.pdf
It doesn't make much sense to create an identification token on the server, send it to the client and set there using Javascript compared to setting it at server-side in the first place.
More importantly, using Javascript makes it compatible with less clients, less robust, and less secure (as you cannot use HTTPOnly cookies).
Main problem is that when your site is used through not encrypted channel (regular HTTP, open WiFi network), everyone can get in possession of that cookie and gain an ability to login in behalf of your user.
There are few protection methods:
encoding browser/workstation-specific data in that cookie,
using HTTPS for everything,
using other storage (not cookies) - it is less possible that a script kiddie with Firesheep will try to capture localStorage data.
Also, as Gumbo mentioned (his comment is now gone and I have no idea, why), this applies for any session-based authentication. So, you PHP session has the same vulnerability (as it is still somehow cookie-based).
Related
A user logs in using default Laravel authentication, which puts an encrypted cookie in the browser, and saves the session in the database.
The user moves to a classic asp page, where I check the cookie value, get the hash, and call the laravel app back passing the session id hash.
Then I use that in laravel to see if there's an active session for that id, and if so I return true, so the user can be logged in, in classic asp.
On each page request in the classic app, I check the last_updated_time in the db and update it on each page. All logging in and out is done in laravel, and classic relies on the database to see if a session is active.
I would also call a public url to get sessions variables and add session variables using laravel, since it's all encrypted and using classic asp for this would be hard.
The only risk I see is session highjacking, but I don't think it's a higher risk than usual.
Is it important to lockdown the laravel URL I call to check if it's a valid session?
Am I missing a security hole here?
Is this method secure?
From what you've stated you probably haven't opened up any security holes. The session cookie is not itself encrypted on the users machine, but you are making sure it is encrypted between their machines and yours, as well as between each of your machines. You should make sure you've set the Secure Flag to help prevent the cookie being accidentally sent over traditional unencrypted transport (HTTP), but as stated, this doesn't effect storing the cookie itself.
That being said, you are essentially hijacking your own users sessions. While a hole might not be introduced now, you are potentially weakening the overall system, which could lead to hole in the future.
Is there a better way to do it?
This might well be a dumb question, but are you sure you need the session? If you're juggling credentials between servers, it sounds more like you want to use Access Tokens and scrap the session.
Using Access Tokens is similar to using sessions, but you need to make your services stateless. This means your no longer storing information about the logged in user any specific machine so you'll need to pull anything you need from the database every time they hit a server requiring that information.
This is a good thing in the long run as it's much easier to scale your services when you don't need to worry so much about where the session is and what's inside it.
OAuth 2.0 is widely used standard (Facebook, Twitter, Google), and was specifically designed to be easy to use. The RFC is complex, but there's a log of good guides out there don't worry.
The one slight down side (if you can call it that) to OAuth 2, is that it MUST happen over an encrypted connection. If your use case can not guarantee encryption over SSL or (preferably) TLS, then you should use OAuth 1.0 (WITH revision A) instead.
This is due to the fact that OAuth 2.0 exposes it's "secret" token in requests, where as OAuth 1.0 only ever uses it to provide a signature hash. If you take this route it's advisable to use someone else's library as the hash is very, specific.
Further Improvement
(Note: This section added after the answer was accepted)
One system I've been exploring recently is Json Web Tokens. These store information about the user to save each machine repeatedly looking it up in a database. Because the token is hashed with a secret, you can be sure that, so long as your secret isn't exposed, a valid token represents a successfully logged in user, without having to touch the database.
You should avoid putting anything too personal in the tokens if possible. If you must store private or secret information in the token, you can encrypt it, or you can use a reverse caching proxy to exchange the JWT for a traditional security token. This may initially seem to defeat the purpose, but it means some of your services may not need database access at all.
I'm no security expert but I don't see an issue with this. The packaged Laravel database session handler works the same way. The cookie contains a hash that references a record in the database. The session data is base64 encoded but that's neither here nor there. I think you could actually avoid rolling your own and just use Laravel's DatabaseSessionHandler.
Illuminate/Session/DatabaseSessionHandler
... I just read a little deeper into your question and noticed the part about the public URL to set and retrieve session data. I think this is a really bad idea. Mostly because it will provide an open door to the end user allowing them to read and write session data. This can only end badly.
Like I said above, the data is only base64 encoded so I believe you'll be able to parse, read and write that to your hearts content within asp.
Edit
Ok... I think this is the last edit. The data is php serialized and then base64 encoded. This question looks like it may help you to that end. If it doesn't and an API endpoint is the only way, find some way to block the end user from accessing it.
Aside from session-hijacking, no. This is the standard way applications interact on a internal basis. Of course there might be a better way to get at the data if you choose a different type of session store other than your database, Memcached for instance.
There are couple of things that can be done.
Make the channel HTTPS. It will make almost impossible to sniff on your transport layer.
Rather than making interactions with your cookie, you could use a JWT to get this task done. Which will help you to use the existing functionality in your system while connecting with ASP system as well. You can write a small REST web service which allows ASP to connect. You could use this lib. You can refer this article which will give you an idea how it should be done.
Please let me know if you need more information.
I'm making an Ajax login system and i wonder if this is secure
Post the username and the password with ajax
Check the login server side, if valid, return the new session id and the user id in a JSON string
Get the JSON with javascript then create the session's cookies "session_id" and "user_id"
Call the page where the logged user is redirected with AJAX
Thanks
Secure for 08/15 website: yes
Secure for online banking: no
The method you use is equivalent to an unencrypted everyday login <form>. Albeit you should really not rely on a "user_id" cookie. Rather save the verified user_id in the session store only.
Also you might try to simply return the session cookie on the JSON result for the AJAX call. It usually sticks to all further HTTP requests, so you don't need (3) to set the cookie via Javascript additionally.
Creating a secure login system is HARD. I would just like to name a few things that could go wrong(bite you in the ass):
unsecure connection(http instead of https).
XSS
CSRF
SQL-injection
unencrypted passwords or simple md5 vulnerable to rainbow table attack.
There a lot of free secure login systems(created by security experts) which you should use instead, for example:
facebook connect
google friend connect
twitter single sign on
openid
I think it could be secure when use post in step 1. already ciphered password and little bit ciphered username, to avoid simple attacks.
Like send(base64_encode(username),md5(password));
And another word, you should check valid session id on server-side, not on client-side in app.
You cannot let client-side script (which could be altered by adv. user) to check session validity.
It's like creating nice and secure API, you have to check everything on server and don't let any dangerous (setting/deleting/creating methods, etc..) opened wordlwide.
I can think of several problems with this idea, in direct order of importance (least to most):
1) Your site won't work for those with JS disabled.
2) Your site may not show the in-browser yellow toolbar to notify the user that SSL/HTTPS is enabled. (Depends on implementation).
3) The user_id parameter is not required client side, and probably not a good idea either. Authentication tokens are almost always just a single identifier, and that's all that is required to prove a user is logged in.
4) It's usually bad practice to write your own authentication capabilities. I know you are not replicating the back-end (which is a very bad idea), but most frameworks already automate the front-end authentication for you and do a good job at it. Use those frameworks, cause they have been tested and are secure. Also, a lot of the time the framework will help you (eg. make it easier to switch authentication providers).
I have been working on a secure login/portal type set of tools, the general code is free from SQL injections, XSS etc, I have mulitple things in place to stop session hijacking.
regenerate session's ID for EVERY page
Compare the user's IP with the IP at login
compare the user's user_agent with the agent at login
have short session time outs
etc
I have done all I can think of to stop hijacking, however I have still located a situation where it might be possible and would like to know if anyone has any ideas.
Imagine a situation where you have 2 users behind a firewall which does SNAT/DNAT, so both apart to come from the same IP. They are both identical machines supplied by the same place. One connects to the site and logs in, the other copies the PHPSESSID cookie and can simply steal the session.
This might sound like an extreme example, however this is very similar to my place of work, everyone is behind a firewall so looks to be the same IP, and all machines are managed/supplied by the IT team, so all have the same version of browser, OS etc etc.
I am trying to think of another way (server side) to stop the hijacking or minimize it further, I was thinking of a token which gets embedded into every URL (changed for each page), and checked.
I am looking for ideas or suggestions, if you want to offer code or examples you're welcome, but I am more interested in out of the box ideas or comments on my token idea.
Force everything to use HTTPS.
I think you are referring to a passive attack where a user in the network sniffs the cookie. For that, you don't need HTTPS. There are several options that are sufficient when the parties are sure to whom they're talking (e.g. you could do a DH exchange first and the server would encrypt a token the client would use in the next request...), but it's not worth the trouble going down that route.
If the user initially types in a non-https address, an active attack is still possible, but there's nothing you can do in that case. In the future, you might prevent future attacks of this kind once the user establishes one unadulterated connection to your site through HTTP strict transport security..
I wrote the main login portal for a major branch of the U.S. military.
I did all you mentioned above, plus at least one more step:
Have you stored a cookie on first login w/ the SESSION salt? Then encrypt everything serverside using that salt. The crooks would have to know about THAT cookie and STEAL IT, and it dramatically reduces exposure to session hijacking, as they just aren't lokoing for it.
Also, use JS and AJAX to detect if they have flash installed and if they do, store a flash cookie, too, with another salt. At that point you can more or less assume you have some pretty dedicated attackers out there and there's not much more you can do (like sending your users GPG keys to use via javascript and make them sign every single bit of data they send to you).
Do not reinvent the wheal, the built in session handler for your platform is very secure.
There are a number of configuration for PHP's session handler. Use HTTPS, at no point can a session ID be transmitted over http "cookie_secure" does this, its a great feature but a terrible name. httponly cookies makes xss harder because javascript cannot access document.cookie. Use_only_cookies stops session fixation, because an attacker cannot influence this value on another domain (unless he has xss, but thats a moot point).
PHP configuration:
session.cookie_httponly=on
session.cookie_secure=on
session.use_only_cookies=on
I am trying to think of another way (server side) to stop the hijacking or minimize it further, I was thinking of a token which gets embedded into every URL (changed for each page), and checked.
You should look at:
Understanding the Rails Authenticity Token
Tokens are a good idea.
I've created a login page and registration page and now I want to use that to password protect pages and have pages which show information specific to that user.
Would storing the user ID of the user logged in in a Session variable be a safe and correct way of doing this?
How easy would it be for a user to change the session variable to a different ID and access another user's information, and not having to type the users login details in?
EDIT: Would posting the user ID from each page to the next be more secure?
Here's an article on session security
If you encrypt user name in such a way that only your PHP scripts can decrypt it then you should be safe I guess.
That's what session meant to be
For session security, you can check http://phpsec.org/projects/guide/4.html
While I'm not aware of any way in which a user could manipulate the information in $_SESSION unless your code (or code on your server) allows them to, so don't do anything crazy like...
foreach($_POST as $key=>$value) { // DON'T DO THIS
$_SESSION[$key] = $value; // DON'T DO THIS!
} // WHY ARE YOU DOING THIS!?
You shouldn't do anything like this, where you're just putting whatever data the user gives you in your $_SESSION variables. Like the database, writing to the session should be thought of as a form of output, and you should sanitize what you put in it (and where it's put) accordingly.
So, unless you're doing something crazy like this (you might be; it can be much more subtle), I don't think you have to worry about a user changing the session variable. You might have to worry about the threats of a shared hosting environment where someone who's probably not quite an end user is manipulating the session info.
What's not so safe is the session identifier, as there are a few straightforward ways to hijack a session in PHP.
I recommend checking out that book I've been linking to, Essential PHP Secutiry. It's a very small and straightforward (but thorough) explanation of several basic PHP security concepts, many of which can be generalized and should be kept in mind when doing any web dev work.
I'll talk about the default session behavior, here: sessions are based on a cookie "PHPSESSID" which is set to an MD5 checksum (32 alphanumeric characters). PHP accepts this cookie from the browser, and uses it to load server-side session data. The client has no direct way to modify data in the session, but does get to specify their own session ID.
You can add additional layers of security (SSL, checking the client IP, etc.), but by default if I know your cookie I can effectively login as you. As far as how "easy" that is, well, that depends on lots of other layers of security: is someone sniffing your traffic, do you have malware installed, etc.
Tools like Suhosin attempt to improve session security.
When a user logins I get him/her's ID and save it in a session var. What I wonder is, is this the way to go? Or should I use cookies? so it automatically login and so on.
session_start();
ifcorrectlogin {
$_SESSION['id'] = mysql_result($loginQuery, 0, 'user_id');
}
how do you authenticate your users?
//Newbie
Yes, this is the way to go. The session itself is already backed by a cookie to remove you any programming efforts around that. The session (actually, the cookie) will live as long as the user has the browser instance open or until the session times out at the server side because the user didn't visit the site for a certain time (usually around 30 minutes).
On login, just put the obtained User in the $_SESSION. On every request on the restricted pages you just check if the logged-in User is available in the $_SESSION and handle the request accordingly, i.e. continue with it or redirect to a login or error page. On logout, just remove the User from the $_SESSION.
If you want to add a Remember me on this computer option, then you'll need to add another cookie yourself which lives longer than the session. You only need to ensure that you generate a long, unique and hard-to-guess value for the cookie, otherwise it's too easy to hack. Look how PHP did it by checking the cookie with the name phpsessionid in your webbrowser.
Cookies can be manipulated very easily. Manage login/logout with Sessions. If you want, you can store the users emailaddress/username in a cookie, and fill the username box for them the next time they visit after the present session has expired.
I would try to find a session engine so you don't have to deal with the misc. security issues that bite you in the ass if you do the slightest thing wrong. I use django which has a session engine built in. I'm not aware of the other offerings in the field although I would assume most frameworks would have one.
The way they did it in django was by placing a cryptographic hash in the user's cookies that gets updated every page view and saving all other session information in a database on your server to prevent user tampering and security issues.
As BalusC mentions, the session_-functions in php are the way to go, your basic idea is sound. But there are still many different realisations, some of them have their pitfalls.
For example, as Jonathan Samson explains, using cookies can result in security holes.
My PHP is a bit rusty, but I remember that the session_-functions can also use session IDs that are encoded in URLs. (There was also an option to have this automatically added to all local links (as GET) and form targets (as POST). But that was not without risks, either.) One way to prevent session hijacking by copying the SID is to remember the IP address and compare it for any request that comes with a valid session ID to to IP that sent this request.
As you can see, the underlying method is only the start, there are many more things to consider. The recommendation by SapphireSun is therefore something to be considered: By using a well tested library, you can gain a good level of security, without using valuable development time for developing your own session system. I would recommend this approach for any system that you want to deploy in the real world.
OTOH, if you want to learn about PHP sessions and security issues, you should definitely do it yourself, if only to understand how not to do it ;-)