Situation:
I have a Javascript/jQuery web app which communicates with a PHP/MySQL/Zend Framework 1.12 backend. The web app runs inside an iFrame (loaded with jQuery fancybox in iframe mode).
The application creates an object on the backend and saves the current session ID with it. It then displays the object's properties on the front end and modifies the object on the backend through ajax calls when the user interacts with the application. The session ID is used to check if ajax requests are coming from the same user (user is not logged in so it's the only way to check).
I use jQuery to do the ajax calls and Zend_Session to work with sessions in PHP/Zend.
Problem:
Now, the problem is that in safari 6, these ajax requests have a different session ID so they don't match the session id stored in the backend model object and access is denied.
This does only happen when running in an iframe, not on any other browsers, not on other versions of safari (5 or below)
Does anyone have an idea what can cause this and how to deal with it?
Some more info:
The entire application runs in the iframe, the call from which the session id is stored in the backend model as well. So I'd think all these calls have the same session id.
Another thing: once I run the application in a separate tab, and then in the iframe again, the issue disappears: from then on until I kill the browser session I get the same session id every time as I would expect. That smells like a bug to me, frankly.
The key issue is the iFrame. As a part of the Safari security model, requests running in iFrames are treated separately from the rest of the page requests. It's part of their 3rd party cookie protections. As I understand it, Firefox22 is going to start doing the same sort of thing, but not quite as restrictively.
If you're sure you really want to get around this, pull PHP's Session Id cookie out and put it on the query string for the request to the iFrame. You can then pull the session id from the query string and use that one. (You won't end up with one in the cookie data if you do this.)
Related
I'm in the process of building a single sign-on system and I am using cURL to send a request off to a file on the main site and return the results / their user data; however, if the user logs into the secondary site via a cookie (ie; they aren't currently logged into the main site) I need to make sure they get logged into the main site at the same time and set some session variables so that they don't continuously have to keep logging in via a cookie on the secondary site.
Obviously we normally would end up with a different session id on the file I am calling via cURL and hence setting any $_SESSION variables there wouldn't be available to the secondary site; so I tried passing the session_id from the secondary site with the call via cURL and then in that file I did this to set the session id so that any $_SESSION variables I set there would then be available to the secondary site.
// Get session ID
$sid = trim($_GET['session_id']);
// Set the session id so we can get the added session data below via the forum
session_id($sid);
session_start();
However when I do that and try and access the secondary site the page won't load, it just hangs - I tried removing that code and loading it again but it won't load until I restart Apache.
Btw.. if it matters, this is on my local dev machine, which is Windows XP Pro.
Any ideas!?
I’m assuming here that both your main and your secondary site are on the same server and use the same session settings, especially the same session.save_path, is that correct?
If so, that’s where your problem lies:
The default session handling mechanism of PHP works using files to save the session data.
And to avoid concurrent write access to the session file, the file gets locked as long as one script (one script instance would be more exact) is still working with the session. Every other script that wants to access that particular session has to “wait”, until the first one is finished using the session.
So with you trying on your secondary site to start your session with the session id already in use on your main site, the script on your secondary site can’t access the session because of that locking.
And since your main site’s cURL request is waiting for the secondary script to finish, which is itself still waiting for access to the session … you’ve got yourself a nice deadlock here :-)
What you can do, is call session_write_close in your main site script before making your cURL request – at that point all data is written to the session file, and the file lock is released.
You have to be aware though, that you can not use the session again in your main site script instance after that – well, you can still read data from and push data into the $_SESSION array, but since the session is already closed, all data that you alter in that array after that point will not be persisted any more. So do what you have to do with the session in your main script, then close the session – and then make your cURL request.
Edit: Well, come to think about it – not sure if the above actually helps here … because your whole approach might be flawed already. Calling a script via cURL on your secondary site will not actually set a session cookie for your secondary domain in the user’s browser – because every response of that secondary site’s script does not “land” in the browser, it lands in your main site script, because that’s where you doing the request from.
I think what you really need here, is to call a script from your secondary site in the user’s browser (JavaScript/AJAX request, iframe, embedded image), so that it’ll set a cookie with the session name and session id as value under your secondary site’s domain – only that will make PHP able to “recognize” the user’s browser once they navigate to your secondary site. Actually opening the session will not be necessary (still assuming that both sites use the same session), because the session is already started, and all it needs for PHP to pick it up on the secondary site is a matching session id from the cookie.
So try doing that instead – but be aware of the problems you might run into with that, since the browser will consider the cookie for the secondary domain as a third party cookie when you are trying to set it in the context of your main site (and the domains don’t match, e.g. one is not running on a subdomain of the other or something like that).
I have created a mobile version of a site. It uses the CodeIgniter session to store some data. This seemed okay on Blackberry a few weeks ago but now it is making multiple sessions on every page and therefore it can't access the session where the data is saved. This works fine on the desktop and iPhone. The cookies are being saved to the Blackberry. I've got it so that it using the database to save the data.
On every page it checks to see whether the phone is touch screen to show the page differently. There is also some other data. It's all being saved but into many sessions.
It's on a subdomain - m.domain.com so I'm wondering if the domain name for the cookie might need to be set differently.
EDIT:
I managed to sort it out by saving the session id in a different cookie and then calling that in a query to get the info. Thank you to the person who replied.
do you proceed you session-id on every link and every form? if not, and the client doesn't accept cookies the session will be lost on every new page load - exactly what you're describing.
EDIT: to correct that, take a look at the documentation (+ Passing the Session ID) - just add the SID-constant to all you links and forms, it will automatically be empty if the browser accepts cookies, so the url isn't that ugly for those clients.
I'm using Codeigniter 1.7.2 with the OBsession library to handle sessions and store them in a database. The app I'm working on consists of a domain (the one with CI) that acts as a service (don't know if this is the correct terminology). Other sites include a JavaScript file from that domain and from there, make an AJAX call to the CI domain. If the site doesn't have a session id, the CI domain returns the one created from that call and then the JS on the site sets a cookie with that session id. From then on, if the site makes any calls to the CI domain it includes that session id in order to identify itself.
This works on every other browser (Mac and PC versions) except for Safari and all Internet Explorers. In Firefox for example, I can see the initial session id get set in the client cookie and in the database and I can make as many calls as I want and as many page refreshes and it still has the same session id in the cookie and database. For Safari, on every page refresh I can see new sessions getting added to my session table.
Any ideas on what is going on here?
Safari and Internet Explorer (with medium security level) does not accept 3rd party cookies by default. A Google search brings:
http://squeeville.com/2010/02/03/third-party-cookies-in-safari-internet-explorer/
Hope this helps.
Obviously the session cookie isn't "sticking" in Safari. Since it's being set by Javascript, you'll have to poke around Safari's debugger (whatever/wherever it is) and see what's blowing up. Perhaps a security model doesn't allow 3rd-party javascript to set cookies, or the browser itself isn't allowing 3rd-party cookies, period.
search for session_start() and paste the logic arround this function...
I would like to know if calling via AJAX or jQuery or whatever the server side, can I clean a session var??
Nowdays I have a FB application that runs with PHP and it's behaviour depends on a PHP session vars, and I would like to clean that session vars on the HTML event unload in the case that the user returns before the lifetime of those vars has passed.
Can it be done??
Presumably, because you are storing this information in session variables, you want it to persist between pages. Therefore, wouldn't clearing this information every time the user leaves a page defeat the purpose?
If you are referring to your PHP app in an iframe, and only clearing it when the user navigates away from the parent frame, I don't believe this can be done, if the parent frame is 'owned' by a different domain.
Yes, but for the static components on the calling page dependent upon session data will not be cleaned due to the stateless nature of the web. It would require a page refresh of some kind.
For example, if I clicked logout button that send an AJAX call to clear my session. I would technically still be logged into the originating page until I refreshed.
If I had a user logged onto my site, having his id stored in $_SESSION, and from his browser he clicked a 'Save' button which would make an AJAX request to the server. Will his $_SESSION and cookies be retained in this request, and can I safely rely on the id being present in the $_SESSION?
The answer is yes:
Sessions are maintained server-side. As far as the server is concerned, there is no difference between an AJAX request and a regular page request. They are both HTTP requests, and they both contain cookie information in the header in the same way.
From the client side, the same cookies will always be sent to the server whether it's a regular request or an AJAX request. The Javascript code does not need to do anything special or even to be aware of this happening, it just works the same as it does with regular requests.
If the PHP file the AJAX requests has a session_start() the session info will be retained. (baring the requests are within the same domain)
What you're really getting at is: are cookies sent to with the AJAX request? Assuming the AJAX request is to the same domain (or within the domain constraints of the cookie), the answer is yes. So AJAX requests back to the same server do retain the same session info (assuming the called scripts issue a session_start() as per any other PHP script wanting access to session information).
Well, not always. Using cookies, you are good. But the "can I safely rely on the id being present" urged me to extend the discussion with an important point (mostly for reference, as the visitor count of this page seems quite high).
PHP can be configured to maintain sessions by URL-rewriting, instead of cookies. (How it's good or bad (<-- see e.g. the topmost comment there) is a separate question, let's now stick to the current one, with just one side-note: the most prominent issue with URL-based sessions -- the blatant visibility of the naked session ID -- is not an issue with internal Ajax calls; but then, if it's turned on for Ajax, it's turned on for the rest of the site, too, so there...)
In case of URL-rewriting (cookieless) sessions, Ajax calls must take care of it themselves that their request URLs are properly crafted. (Or you can roll your own custom solution. You can even resort to maintaining sessions on the client side, in less demanding cases.) The point is the explicit care needed for session continuity, if not using cookies:
If the Ajax calls just extract URLs verbatim from the HTML (as received from PHP), that should be OK, as they are already cooked (umm, cookified).
If they need to assemble request URIs themselves, the session ID needs to be added to the URL manually. (Check here, or the page sources generated by PHP (with URL-rewriting on) to see how to do it.)
From OWASP.org:
Effectively, the web application can use both mechanisms, cookies or
URL parameters, or even switch from one to the other (automatic URL
rewriting) if certain conditions are met (for example, the existence
of web clients without cookies support or when cookies are not
accepted due to user privacy concerns).
From a Ruby-forum post:
When using php with cookies, the session ID will automatically be sent in the request headers even for Ajax XMLHttpRequests. If you
use or allow URL-based php sessions, you'll have to add the session id
to every Ajax request url.
It is very important that AJAX requests retain session. The easiest example is when you try to do an AJAX request for the admin panel, let's say. Of course that you will protect the page that you make the request to, not to accessible by others who don't have the session you get after administrator login.
Makes sense?
One thing to watch out for though, particularly if you are using a framework, is to check if the application is regenerating session ids between requests - anything that depends explicitly on the session id will run into problems, although obviously the rest of the data in the session will unaffected.
If the application is regenerating session ids like this then you can end up with a situation where an ajax request in effect invalidates / replaces the session id in the requesting page.
That's what frameworks do, e.g. if you initialize session in Front Controller or boostrap script, you won't have to care about it's initalization either for page controllers or ajax controllers. PHP frameworks are not a panacea, but they do so many useful things like this!
put your session() auth in all server side pages accepting an ajax request:
if(require_once("auth.php")) {
//run json code
}
// do nothing otherwise
that's about the only way I've ever done it.