Coles Notes version:
index.php?map_id=foo is loaded into iframe on www.not-my-domain.com. index sets SESSION['map_id'] = foo. Flash file tries to get SESSION['map_id'] thru Authenticate.php, but Authenticate.php has no values set for any SESSION varaibles.
-- Only first-load, cross domain issue.
Verbose:
I have an index while where I set: SESSION['map_id'] = foo
The index file then loads a flash file. When initialized, the flash accesses an 'Authenticate.php' file which echo's out the SESSION['map_id'] and is loaded into flash via LoadVars. Flash then displays the appropriate data.
This step cannot be done another way
This all works just fine on our main site. The issue comes when we try to port out to other sites by providing iframe embed codes:
<iframe src="http://www.mydomain.com/?map_id=foo&code=bar" ... ></iframe>
On a fresh load of the embed code from another site (www.anotherdomain.com), it seems that the SESSION variables have been destroyed, as flash simply says they are empty. ( $map_id outputs a blank )
The index file will still properly echo $map_id as 'foo', it just seems the 'Authenticate.php' file cannot access the SESSION varaibles.
I have ensured session_start() is present in all appropriate files.
PHP session ids are passed through cookies by default, but you can't transfer cookies across domains. Try passing the session id through the url instead.
Here is the appropriate page in the php documentation.
There are a few ways you can get php to pass the session id in the url if it's not being done automatically.
You can manually pass the session id in the url (must come before other get variables):
<iframe src="http://www.mydomain.com/?&map_id=foo&code=bar">
You can disable cookies, forcing every request to have the session id automatically added to the url:
ini_set("session.use_cookies","0");
You can edit the url_rewriter.tags setting, which tells PHP which html tags to rewrite with the session id. Here, iframe=src has been added to the default set:
ini_set("url_rewriter.tags", "a=href,area=href,frame=src,iframe=src,input=src,form=fakeentry");
Related
Just a newbie here so please pardon my mistakes.
I'm working on a website using .shtml pages (SSI).
I'm trying to include a PHP script into my .shtml page.
Up to this point everything is working fine:
PHP script gets included and it does what it was intended for.
Here is the actual example.
There is the home page (index.shtml) including a script called security_check.php with this directive:
<!--#include virtual="includes/security_check.php?idOp=000&idPage=0000" -->
This is the PHP code for security_check.php:
<?php
session_start();
include('config.php');
include('myfunctions.php');
include('security_functions.php');
$idOp = $_GET['idOp'];
$idPage = $_GET['idPage'];
$allowedReferer = array();
// Connection to the database (defined in myfunctions.php)
$link = DB_Connect($DBhost, $DBuser, $DBpass, 1, $DBname);
// Check if the PHP session already exists. If not, create one
// (that is insert a record in the DB and returns the id, which
// will be stored in the PHP session variable).
// user ID is 0 because not logged yet
if (!isset($_SESSION['idSess'])) {
$_SESSION['idUser'] = 0;
$_SESSION['idSess'] = create_session(); // security_functions.php
}
// Please note that create_session() correctly use $_SESSION['idUser']
// in order to do its work, even if it's not passed as a parameter
// (as it should be: $_SESSION is a superglobal!) and the same goes
// for activity_supervisor().
// Defined in security_functions.php:
// it uses both $_SESSION['idUser'] and $_SESSION['idSess']
activity_supervisor($idPage,$allowedReferer,2,$link);
mysql_close($link);
?>
At this point,
home page is correctly displayed and there is a 'Sign up' button
in it, calling sign.shtml.
This sign.shtml page include the very same security_check.php script
with the exact same include directive already seen above except for the value of idPage parameter which in this case is 0001.
I would expect the script to recognize the PHP session and therefore
not creating a new session, but indeed a new session gets created every time.
I already read every other post related to PHP sessions not working and I even tried the solutions proposed there.
- session_start() is written on top of every script because there is just one script
- session.save_path equals to /var/lib/php/session and is writeable by the web server
- I already tried to set session.gc_probability = 0 and restarting the web server (to no avail, so I got back to session.gc_probability = 1)
- I tried with different browsers (namely, Firefox and Chrome) with the same results
So I tried the following test (note those two empty lines BEFORE session_start(): I always space instructions this way to improve readability)
creating a simple test.php script
<?php
session_start();
if (!isset($_SESSION['foo'])) {
$_SESSION['foo'] = 1;
echo ('Value is '.$_SESSION['foo'].'<br/>');
echo ('Refresh');
}
else {
$_SESSION['foo']++;
echo ('Value is '.$_SESSION['foo'].'<br/>');
echo ('Refresh');
}
?>
Well, believe it or not, every time I hit 'Refresh', the value
is incremented, so PHP recognize the session (the test.php script is inside the same domain as the index.shtml and sign.shtml pages).
I even tried to make the PHP script to show a link to a .html file (not .shtml) which then show a link to test.php. It works correctly!
It really seems that the session is not correctly set only when the PHP script is included into the .shtml page, even if I don't see any reason for that. Maybe you know why and, above all, how to circumvent this boring behaviour? Is it a feature? Does it depend on a parameter setting in php.ini?
Final tips:
OS: CentOS 6.3 with 2.6.32-279.el6.x86_64 kernel
Server version: Apache/2.2.15 (Unix)
PHP 5.3.3
Server is mine so I can configure everything, if needed.
Thanks in advance and forgive me for the long post: I tried to make it
clear that PHP sessions do work perfectly in every other situation I know of.
I don't think this will work because the SSI will execute the PHP script, and then send out its output to the web server. You would need some way of rewriting URLs so that they do not rely on cookies, since cookies get "eaten" before the server gets to send them to the browser.
Try using
ini_set("session.use_cookies",0);
ini_set("session.use_trans_sid",1);
and then you'll need to send the SID in the outgoing URLs (and on POST pages, too). See this answer for example.
Specifically, you need to redirect the user not to sign.shtml but to something like
$sidkey = session_name();
$sidval = session_id();
print "sign up: here";
and include this in the SSI output.
UPDATE: the root of the problem is that the SSI cannot create a session (cannot send anything but plain HTML. Sessions that use cookies rely on headers, not HTML only). But if you create the session with a PHP script launched outside SSI, that is able to set a cookie, from that point onwards all PHP scripts (whether SSI or not) are able to read the cookie and therefore will be able to access and modify the session (which is a file/memory/Redis/other on the server identified by the session cookie's value).
You can check whether a cookie is set in SSI, and if it not, you can redirect to a pure PHP page that sets the session cookie and sends back to the original shtml using a HTTP Redirect.
So in my HTML markup I have an image tag like this one:
<img src="image_generation.php" alt="template" id="image" />
And the 'src' attribute links to a PHP script that generates an image using a couple of variables defined there which are mostly randomly generated.
Now, what I want to be able to do is to access those random variables in the page which includes the image generation script. I suppose I could send cookies and access them after the image tag as they technically should be readily available to the including file. I don't want to send too much information, just a couple (10-20) variables. Not sure if in that case sessions would be a better choice, as I would have to send several cookies. Sessions also pose a problem as the including script gets the old session and I would have to refresh the page to obtain the values of the previously generated image. I suppose I could also set up a DB and access the DB in the including script, but the variables are temporary and I would have to delete them and that seems like a lot of fuss to me.
The image generation script finishes with:
header('Content-type: image/png');
imagepng($image);
imagedestroy($image);
And nothing can be sent to the browser before the header call or else the image won't be displayed. If I use cookies or sessions, the image_generation.php would have to send both the image and set the cookie(s)/session.
None of the options (cookies, sessions or DB) really convince me, as there are problems with each in this particular situation. Can you think of a way to solve this? Thanks.
MAJOR EDIT #1:
Including script gets session of previously generated image without refreshing / Setting cookie(s) and/or a session in included script before / after sending image without output buffering does not pose a problem.
You can use a $_SESSION, but to make the session available in the same script that included the <img> tag (which would have executed before the image script), you would need to make AJAX calls via JavaScript. An AJAX handler that runs at window.onload should have access to the $_SESSION created by the image script, since the image should have fully loaded when it executes.
Example PHP handler getsession.php:
header('Content-type: application/json');
// Simply part of the session into JSON
// Obviously you would want to limit this to only the variables
// that should be sent back, so you don't expose the session on the client side!
echo json_encode(array($_SESSION['var1'],$_SESSION['var2']));
exit();
Example AJAX call (using jQuery since it will be easy to get started with)
// Variable to hold the object returned by PHP
var imgPHPSession;
$(window).load(function() {
$.ajax({
url: 'getsession.php',
dataType: 'json',
success: function(data) {
imgPHPSession = data;
}
});
});
Update:
It can be done entirely in PHP, but would require changing your design a bit such that the variables necessary to generate the image are created in $_SESSION by the main script. They are then available in $_SESSION to image_generation.php to be used as needed, but are already known to the main script.
Update 2:
Since the image vars contain info about how it was created, if the image is not too large, you can actually create it in the main script and store it to disk. The image_generation.php script can still be used as the <img src>, but its purpose would then be to retrieve the correct image from disk and serve it back to the browser and delete it from disk when no longer needed. The $_SESSION is then available to both the main and image scripts.
You can pass you parameters to src attribute, for example:
<img src="image_generation.php/user/1/name/tom/param1/variable2"
or
<img src="image_generation.php?user=1&name=tom
this solution lets you forget about session, cookies - it's stateless
Php can do smart tricks with buffer by ob_* function, so at the beginning of your script you can call ob_start() to buffer every php output, it lets you avoid all 'Header already send' errors.
Your image_generation.php does not need to send any cookie. This script will receive cookie with sessionid (browser attach cookie information to every request to the server) what makes possible identify user session on php side - after that you have access to every session parameters.
I think I forgetting something in my code but can't find what.
On my server I have simple logging.php file.
If I pass user/password parameters then a new session is created.
If I pass loggout the session is destroyed.
If I pass report the list of current session variables are reported on screen.
If I test the code writing urls in my browser all works fine. First invoke .../logging.php?user=xxx&password=xxx. The session is started and the session variables are reported to me. And finally I destroy the session passing the logout parameter.
If user request a report or a logout and no session exists a HTTP-401 error code is returned to client.
On the other hand I have a piece of JavaScript code that I can inject on web page using a bookmarklet. Once code is injected I show a toolbar where user can write user/password and send to server.
The logging actions seems to works fine, and server returns me a 200 status code, but later if I make a request to logout the server returns me a 401 error, which mean no session exists.
I was using chrome and looking at HTTP request and responses can see that when I logging the server returns in the response different values for PHPSESSIONID.
That means two different AJAX request are considered different sessions. The server seems to not recognize the second request from AJAX as if it was started by the same client.
Repeat, the PHP code works fine if I execute using browser directly but not with AJAX request, so I think I forgetting something in AJAX.
Any ideas?
Thanks in advance.
Update
To be more concise, my problem is calling php from JavaScript. It seems there are no sessions started.
Imagine a very simple PHP code:
logging.php: given a user/password starts a new session and also stores 'user' names as a session variable.
request.php: which returns the user name stored as session variable.
logout.php: which destroys the session.
My first AJAX request start a PHP session. That seems fine because a PHPSESSIONID cookie is returned from server. Also I store the user name as session variable.
The second AJAX request tries to get the user name (stored in the session) but it gets nothing and in addition a new PHPSESSIONID cookie is returned from server.
I know it seems impossible and more when I'm testing using browser url request and works fine, but it's the truth.
I'm forgetting something on AJAX, expiration times or something similar?
Update again
I made some tests and I found the problem but not the solution.
My JS code is injected through a bookmarklet.
When I inject the code in a HTML page from my server, the AJAX requests works fine. The first (logging) request gets a PHPSESSID which is passed in subsequent request to the server.
On the other hand If I load google.com and inject the code, the first (logging) request gets the PHPSESSID too but later it is not sent with next requests.
Anyone has experienced the same issue? which is the problem?
Thanks in advance.
Update again, again
Ok finally I found my problem. Because my JS is injected from a different domain (current page is from domainA and my JS code comes from domainB) cookies are not cross domain, so PHPSESSID can be shared.
A possible soulution is when I logging I will return the PHP session ID in pice of JSON data and use it for subsequent calls.
If I'm correct, you're trying to log in a user by making an AJAX request to a URL, with the username and password provided in the URL? That's not really a safe construction, the password is very vulnerable this way?!
I would advice you to implement jQuery, and transer the login details using the $.POST command:
http://api.jquery.com/jQuery.post/
Make sure all your files (also those requested by AJAX) contain session_start(); on top of the file.
When every file contains session_start(); and you're using the same $_SESSION variables to check if a user is loggedin, it should work!
Are both of your AJAX requests coming from the same page? The requests are Asynchronous, so it may be that the "logged in?" request is returning its result before the "log in" request goes through.
From what you have asked, I hope your code is (at its beginning more or less) something like:
A file logging.php like this:
<?php # file : loggging.php
if(!ini_set('session.auto_start'))
// more stuff
if(!empty($_REQUEST['user']) && !empty($_REQUEST['passwd'])) {
session_regenerate_sid(); // This is important (1)
$_SESSION['user'] = $_REQUEST['user'];
// Whatever
}
A file request.php like this..
<?php # file : request.php
if(!ini_set('session.auto_start'))
// Whatever stuff to process data
var_dump($_SESSION);
// Or a nice foreach($v as $i => $x) {
// echo("[$i] => $x\n<br />");
// } instead :)
And your logout.php should read something like..
<?php # file : logout.php
if(!ini_set('session.auto_start')) session_start();
session_destroy();
You are probably not calling either session_start() or you are calling it twice.
To check this out try this: change all your session_start() lines for:
session_name('MYCoolNewName');
session_start();
Now your session should not read PHPSESSID, instead it should be MYCoolNewName.
If it is not, then your problem is the aforementioned.
(1) I put as important session_regenerate_sid() because opened authenticated sessions are a threat out there. I'll demonstrate it with an example.
Alice visits coolwebsite.com/login.php, which gives her a SID which I'll call AliceSID.
Alice tells Bob to visit coolwebsite.com/login.php?PHPSESSID=AliceSID, and when Bob does Alice could log in his account unless Bob's session was regenerated.
That's my problem: I have an website, example.com, in which index.html file a introduced a <script src="website.net/js.js"></script> You can see, that this is on other web server.
In the js.js I have some data that I want to send to php. For that, I am using Ajax. So, I made a request to "website.net/data.php" using method get. In data.php file everything is ok,I received the value, but I want to set a cookie which value is what I received through ajax. Here is the problem. The setcookie function says that the cookie was set, but when I check in the browser, there's no cookie!
It works fine if the index.html file where I use <script src="website.net/js.js"></script> is hosted on the same domain where I am making the request. If it is on another domain, it doesn't work anymore.
I have read something about Ajax cross site, but I don't want to send something back to example.com. All I want is to send some data from example.com to website.net and then setting a cookie based on that value.
From the example.net I take a single value. On website.net I receive that value, I check if it's not already a cookie set, if it's not, I set it. On the same page, website.net, I use this cookie too.
Where do you check if the cookie is set? On the domain example.com or on the domain website.net?
In case you try to access the cookie using example.com, it is simply not possible to write/access or do anything with a cookie of an other domain. This is for security reasons. If you could, every other website could access you cookie and steal your identity easily.
Try to set the cookie within an iframe. I'm not sure if you can actually set cookies for website.net using JavaScript just because js.js is loaded from that domain.
Thank you very much!
I found an other way to send the data to a php file without ajax using basic javascript and <img /> tag
For example:
example.com has in index:
<script type="text/javscript" src="http://website.net/js.js"></script>
In the js.js file I have
var important_data = 123; //
var src = "http://website.net/process.php?important_data=" + important_data;
document.write('<img src="' + src + '"/> ');
Now, every time I load example.com, it sends to website.net the important data. I tried to set a cookie in process.php file and it worked! I tested that idea on localhost (both 'websites' were in my local server), but it should works also between 2 different domains. I'll try to see if it works between 2 different websites. After that, I'll come back to share the result.
Thank you!
Later Edit:
I checked if I can set a cookie using that method, and it works!
It works great! The cookie for website.net is not setted for that domain, it is setted for example.com. Exactly how I want!
Using JSONP on a site say xyz.com, I am calling a site abc.com/test.php. However, everytime I call this site, I get a new session id in IE6 and IE7. In other browsers it remains constant.
The code of test.php is something like:
<?php
session_start();
echo session_id();
?>
However, after I visit http://abc.com/test.php in another window, and then refresh my page at xyz.com with JSONP code, it shows a constant ID. I have no clue why. Any suggestions?
This happens only in IE6 and IE7. Rest all work as expected. Somehow IE6 and IE7 dont seam to retain the session id (i.e. cookie name) until I actually visit the site in another window.
Based on some info on PHP.net, will adding this header work?
<?php header('P3P: CP="CAO PSA OUR"'); ?>
Quote:
"workaround when using session variables in a .php file referred by a frame (.html, or
other file type) at a different server than the one serving the .php:
Under these conditions IE6 or later silently refuses the session cookie that is
attempted to create (either implicitly or explicitly by invoquing session_start()).
As a consequence, your session variable will return an empty value.
According to MS kb, the workaround is to add a header that says your remote .php page
will not abuse from the fact that permission has been granted.
Place this header on the .php file that will create/update the session variables you want:"
If this doesn't solve it, it might be something to do with the HTTReferer as IE doesn't send it on requests that initiate from JavaScript (e.g. doing this in IE will fail to send the HTTR Referer document.location.href = 'http://example.com/';