I have a login screen that I force to be ssl, so like this:
https://www.foobar.com/login
then after they login, they get moved to the homepage:
https://www.foobar.com/dashbaord
However, I want to move people off of SSL once logged in (to save CPU), so just after checking that they are in fact logged in on https://www.foobar.com/dashbaord I move them to
http://www.foobar.com/dashbaord
Well this always seems to wipe out the session variables, because when the page runs again, it confirms they are logged in (as all pages do) and session appears not to exist, so it moves them to the login screen.
Oddness/findings:
List item
The second login always works, and happily gets me to http://www.foobar.com/dashbaord
It successfully creates a cookie the first login
If I login twice, then logout, and login again, I don't need two logins (I seem to have traced this to the fact that the cookie exists). If I delete the cookie, I'm back to two logins.
After the second login, I can move from non-ssl from ssl and the session persists.
On the first login, the move to the non-ssl site wipes out the session entirely, manually moving back to the ssl site still forces me to login again.
The second login using the exact same mechanism as the first, over ssl
What I tried:
Playing with Cake's settings for security.level and session.checkagent - nothing
Having cake store the sessions in db (as opposed to file system) - nothing
Testing in FF, IE, Chrome on an XP machine.
So I feel like this is something related to the cookie being created but not being read.
Environment:
1. Debian
2. Apache 2
3. Mysql 4
4. PHP 5
5. CakePHP
6. Sessions are being saved PHP default, as files
I figured this out. Cake was switching the session.cookie_secure ini value on-the-fly while under SSL connections automatically, So the cookie being created was a secure cookie, which the second page wouldn't recognize.
Solution, comment out /cake/lib/session.php line 420 ish:
ini_set('session.cookie_secure', 1);
(Just search for that to find it, as I'm sure the line # will change as releases come out.)
While the accepted answer meets the OP's desire to "move people off of SSL once logged in" - it's horribly insecure in that it exposes the user session to hijacking (See Firesheep for an easy exploit).
A better compromise between the default behavior of CakePHP (which requires all pages to be served SSL after a user authenticates over SSL) and the accepted answer (which serves all authenticated pages unencrypted and exposes the authenticated cookie) is to serve pages encrypted over SSL if and only if they require authentication.
An easy way to accomplish this is to maintain two session cookies - one that is served secure and holds the authentication information and another which is served insecure. A simple implementation to support such a dual-session approach will use a session_handler to override the session.name like so:
if (env('HTTPS')) {
ini_set('session.name', Configure::read('Session.cookie').'-SECURE');
}else{
ini_set('session.name', Configure::read('Session.cookie'));
}
One item to keep in mind with this approach is that to link from a non-SSL page directly to a page that requires authentication will require you to explicitly link using https - since you'll need to send the session cookie containing the authentication information and the browser will only do so if the link is encrypted.
First of all, do I understand correctly that the second login is using the exact same mechanism as the first (via HTTPS)?
Does the first hit on a unsecured page create a new session, in addition to the one created during login?
Check if, on first login, the cookie is not set with the Secure flag (that means that the cookie should only be sent over a secured (HTTPS) connection).
You can specify your own session handling settings in a configuration file (rather than editing the CakePHP library file.) In the configuration file you can set session.cookie_secure to 0, which will take precedence over the setting in /cake/lib/session.php. This will allow the session cookie to be used for both SSL and non-SSL connections.
Here is a blog entry on the topic:
http://bakery.cakephp.org/articles/view/how-to-bend-cakephp-s-session-handling-to-your-needs
and some documentation from the Cookbook:
http://book.cakephp.org/view/173/Sessions
You can read more in documentation CakePHP at
http://book.cakephp.org/2.0/en/development/sessions.html
CakePHP’s defaults to setting session.cookie_secure to true, when your application is on an SSL protocol. If your application serves from both SSL and non-SSL protocols, then you might have problems with sessions being lost. If you need access to the session on both SSL and non-SSL domains you will want to disable this:
You open file Config/core.php and add as bellow
Configure::write('Session', array(
'defaults' => 'php',
'ini' => array(
'session.cookie_secure' => false
)
));
Now you can switch http and https that not lose session :)
Has your homepage got any flash on it that makes a subsequent request to your server? Or any Ajax loading of content?
Have you checked headers being sent from the server? In IE you can use Fiddler or in Firefox use the Live Headers addon. Check for any new cookies being set or the CAKEPHP cookie having a different value.
Just bumped into this problem, I commented the following and it worked fine:
<br />ini_set('session.name', Configure::read('Session.cookie'));
<br />
from session.php (/cake/lib/session.php, line 480~)
Related
I made a website that has an integrated shopping cart. Of course, I use a lot of session variables to do this. When I uploaded the site to inmotion hosting and made it an SSL connection, my session variables stopped transferring over? I have no idea why. I think part of it is because the sites are originally HTTP, then they are being forced to change to https, thus losing the session?
Any help would be amazing!
Ok I have tried changing the cookie domain and the cookie secure in the php.ini files but neither has helped. Please help!
Cookies have a secure flag on them which means that they can't be used on http sites. At HTTP connection, when you session_start(), PHP creates a new session id, which replaces the previous session id.
I believe you can unset that with session.cookie_secure = 1 in php.ini
Here's the thing:
I have Website A in Server 1, a CakePHP 2 based website without any kind of login system.
I also have Website B in Server 2, another CakePHP website which has its login system (uses CakePHP's Auth for more details if it matters), with a login form in first page where users can enter login/password to access it.
So now what I need to do is to add a login form in website A that logs users into website B (as if they had used the form in website B).
Is that possible? If so, what approach should I take to do that securely? (By that I mean without plainly exposing the users credentials).
I assume you're doing this so that you can go between multiple sites, but only login once? I've come up with a way to do this, provided that the sites share domains, but are hosted on different subdomains by getting them to share session. The reason this only works on websites that share domains is because two completely unrelated websites cannot share cookies, which is necessary to get them to share session.
Note that since your goal is to make the two servers completely share their sessions, you will encounter some problems, like for example, flashmessages for one site will appear on both. I ended up extending the Session component so that it would automatically append to all session variables with a prefix to specify which server the session variable belongs to.
Here's an outline of the steps:
The login server will need to be able to host shared sessions, probably via memcache's session save handler, which you will need to install on both your servers. See more here: http://www.dotdeb.org/2008/08/25/storing-your-php-sessions-using-memcached/
The login server's site will need all the regular stuff for a login system, but you also need to set the server up so that it will use the shared memcache session instead of the normal way of saving session. Example once you have memcache installed, add to its php.ini file:
session.save_handler = memcache
session.save_path = "tcp://[login server ip]:11211"
The other server's site will also need to use the shared memcache session stored on the login server, so config its php.ini the same way you did for your login server. Then, set up the Auth component on this site so that it will require logins, but for actually logging in, redirect them back to your login server.
On both servers, in bootstrap.php, add the line ini_set('session.cookie_domain', '.' . ROOT_DOMAIN); Where root domain is the root domain both of them have. So if you were using test.com and subdomain.test.com, ROOT_DOMAIN would be "test". This way, the websites will also share their session cookies.
Make absolutely sure both servers are set to the same time. If their times don't match, you'll likely randomly lose your session because one of the servers will think the session is much older than the other server, and so it will delete it because it thinks the session is too old.
Sorry for the confusion. To clarify my question, the session will be created over ssl and will stay encrypted. While users browse using normal http, I'm asking if I "require" a ssl page that verifies the users' session, will it run in ssl or will it simply be a part of the parent page which is in http which will be unable to retrieve the session id because the session is saved in https.
I'm currently working on a secure member log in with php.
A log in form will redirect to a ssl url (i.e. https) to keep the password safe for people who are logging in using unencrypted network/wifi.
The only problem is, I can't think of any way to "securely" pass users' log in session from https to http.
So I was thinking to use "require_once" from php which includes a file url starting with https. And the included file will create a session under https and all I have to do is simply require the page in every authentication-required page.
The only issue is, I'm not too sure if the "required file" will run under https or the codes will simply be included in the parent page and run under http.
In other words, how exactly does include or require work (does the function run the code in the separate page or simply include the code in the parent page and run)? I searched php manual, but I was't able to find the answer. Also, I can't test it by myself because I don't have ssl license yet.
Also, any suggestion on building a secure log in using https (just for log in) in combination with http for any other user interface?
include() and require() will only go 'external' and do an HTTP-type request if the path you're providing to them looks like a url (e.g. 'http://....'). Otherwise it's interpreted as a local file file request and does NOT involve the HTTP layer.
There's no practical difference to PHP if a script was requested via HTTP or HTTPS, except there'll be extra SSL-specific entries in $_SERVER. Includes/requires still work as they if the script was running in a non-SSL environment, and the script can still do CURL requests and whatnot. Remember that the SSL link is established by the server and the client browser BEFORE php is invoked, and applies only to do the client<->server communications. Anything the script does with external resources will only involve SSL if the resources requested themselves are done via a completely separate SSL request.
You cannot "turn on" SSL from within a PHP script. There's no mechanism in HTTP to dynamically migrate a link from a regular unencrypted port 80 to an encrypted port 443 within the same request. You can redirect the client towards an SSL url, but that involves a completely new HTTP request - the original request started as non-SSL and will stay non-SSL.
Edit: The below is an answer to the original question, which was phrased in a way that made it sound like the author only wanted the login page to be protected.
I assume that the reason you want to redirect back to HTTP is that the site contents itself isn't confidential, and that you only care about protecting the user's password and account. However, if you redirect the user back to HTTP after logging in, your site will be almost as insecure as if you didn't use HTTPS at all. Granted, HTTPS login will prevent the user's password from being sniffed, but anyone can use Firesheep or similar applications to steal the user's session id after login if you redirect back to HTTP - then, they can take over the account by changing the password (or simply act as the user without changing the password).
(While we're on the subject: why on Earth doesn't StackOverflow use HTTPS after login?) :-(
In order to maintain security, you need to ensure the https:// is in the user's address bar at all times. You can't just include a file and expect it to be secure.
Think of it this way. Say you have a form on http:// and you make a curl call to https:// # Verisign to post a credit card payment. That unencrypted data can easily be intercepted before it reaches Verisign's secure page.
If it's SSL, keep it SSL throughout the entire session. You'll notice on bank sites, there is usually a login button which directs you to an https:// page containing the form - OR they mix it by grabbing your username on the http:// page and then posting that to the https:// page before asking for your password. US Bank does this just to get the user engaged on the home page.
EDIT:
To respond to the new clarification. I would not let a user browse http:// pages while logged in via https://. I would add this logic:
if(isset($_SESSION['LOGGED_IN_SSL']))
{
if ($_SERVER['HTTPS'] != "on")
{
$url = "https://". $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
header("Location: $url");
exit();
}
}
That would force the user to view the https:// version of whatever page he/she wishes to view.
My web application is receiving increased attention and I need to provide additional security to protect my customers.
The biggest problem as I see it is that the user login data is sent as plain text. My goal with this question is to discern if the following approach is an improvement or not.
In extension I will need to get dedicated servers for my service. This proposed solution is temporary until then.
I am currently running my web application on a shared hosting web server which only provides SSL through their own domain.
http://mydomain.com
is equivalent to
https://mydomain-com.secureserver.com
My thought is to have:
http://mydomain.com/login.php
...in which an iframe opens a page from the secure server, something like this:
<iframe src="http://mydomain-com.secureserver.com/ssllogin.php"></iframe>
I authenticate the user in
ssllogin.php with the (hashed+(per
user based-randomly salted))
passwords from the database.
After proper session regeneration set a session verifying the authentication.
This session is then somehow transferred and verified on http://mydomain.com
Is this approach even possible to achieve? Would this be an improvement of my login security or just move the "point of interception of password" for the attacker to another instance?
All feedback is appreciated.
You don't need an iframe. Just make the action of the login form to point to https://yourdomain.com/login.php . In there you may check if user & password are correct, and then redirect again to plain http.
BUT this is not 100% secure. The fact that you are sending the user & password via https may prevent an attacker or sniffer to get that. But if you later revert to plain http, it is possible to this attacker/sniffer to hijack the session of any logged in user sniffing the session cookies of this user.
If you want more security (not 100%, but more than this previous option), stay always in https, for all resources (css, js, images too, not just your php/html files), and even serve the login page via https.
For some reasoning of these points, see firesheep (for the hijacking session problems) or the recent tunisian gov't attack on tunisian facebook/yahoo/gmail users (for serving even the login page via https).
edit: sorry, I misread your question. If the SSL domain is different than the not-ssl domain, you may have problems, as the session cookie only will work against the same domain or subdomains. So, if you do the login and send the session cookie from https://yourdomain.secure-server.com, it will only be sent back by the browser to yourdomain.secure-server.com (or *.secure-server.com if you will), but not to yourdomain.com. I think it's possible to make a wildcard cookie valid for all *.com subdomains, but it's better not to do this (do you want your users' session cookie be sent to evil.com ?)
we've recently done some installation but I'm facing issues with one pc in particular and its baffling. We have a webapplication installed on our local server which is accessed by all our workstations. FOr some reason we can't log into our webapplication using one workstation. The application is a PHP MYSQL collaboration system. I double checked and for some really odd reason whenever we login it creates a session ID but upon logging in and redirecting to another page the session is broken and a new session id is generated thus the individual is automatically logged out again.
What could be the issue here - is its a firewall thing - its not the web application as we can access it fine via the other workstations. We even disabled the firewall but in all cases that single dumb workstation seems to have an issue with maintaining the session.
Help please - I'm sure its an issue confined to that one PC - what could it be.
Update
The authentication sequence is as follows:
Login
Authenticate user
Build session
Store session variables with session ID in db
Redirect
SESSION variables are empty - a new session ID is generated
Since new session ID is not of an authenticated user - return to login
More details
SSL is not enabled
Cookies are enabled are on the problem machine
UPDATE
I don't understand how can redirection be the problem here. My redirection code is as follows I'm using the following function to redirect to the index page upon successful login.
function _redirect($url)
{
#To redirect to a specified page
if(headers_sent())
echo "<meta http-equiv=\"refresh\" content=\"0;URL=$url\">";
else
header("Location:$url");
exit;
}
Plus even if it is an issue why is it a problem on just one PC and not on the others? I don't wish to change my code just to accommodate one system as opposed to fixing whats wrong with that one system which is preventing it from behaving in the first place.
MORE UPDATE
I just double checked and found something odd. My login is ajax based i.e. a request is made via ajax if it is a success the session variables are generated and a boolean 1 is sent back upon receiving the user is redirected via a javascript call which is:
function _redirect(url)
{
window.location = url;
}
I commented out this call and instead when the user is logged in I manually go to the index page and it works fine!! What is the javascript redirect messing up in this one pc thats not messing up in the other workstations is beyond me :( How do I fix this?
It sounds like the cookie is not being set and sent back to the server properly on this machine. Verify that you have cookies enabled and that you don't have some 3rd party browser extension or other software blocking cookies.
what browser are you using on this workstation? IE? Firefox? Have you tried different web browsers? Tried checking the browser settings yet? What is the time out set to? Is the time on the server and workstartion syncing properly with ntp?
In IE you can disable accepting of sessions cookies if the security is set to high I believe.
If you're losing the session, it's likely because the session cookie is not being transmitted. Does the browser on that machine have cookies enabled? Are you using SSL for your login page? Does your login code do anything besides validate a username/password (e.g. validate an IP address or machine name)?
Edit
Can you verify with Fiddler/Wireshark that the session cookie is transmitted when you redirect? Can we see some example login code?
I misunderstood the question to begin with (hence my edit history)
What is the domain the login is on and the main site is on? If it's between domains (could be anything like sending between example.com and www.example.com)