PHP sessions across 2 subdomains
This is an addition to PHP sessions on subdomains
I tried what is stated in this question and I see that the problem was not given.
So, I need to have sessions between subdomains ( www.example.com
before forum.example.com
)
What I did on www.example.com
,
session_name("a_name");
session_set_cookie_params(0, '/', '.example.com');
session_start();
echo session_id();
$_SESSION['test'] = 123;
On forum.example.com
session_name("a_name");
session_set_cookie_params(0, '/', '.example.com');
session_start();
echo session_id();
print_r($_SESSION);
Session_id is exactly the same, but $ _SESSION doesn't output anything.
How to make a conclusion forum.example.com
123
?
I tried session.cookie_domain = .example.com
but didn't change anything
When I go to forum.example.com
it destroys sessions www.example.com
and it does the same on the other side, for example if it detects that it comes from a different subdomain and wipes everything out for security.
2 subdomains are on the same Debian server
Another thing I noticed is that without session_name
and session_set_cookie_params
it still has exactly the same session_id when I setsession.cookie_domain
thank
source to share
Ok, I thought about this for a while and I think I got it.
First of all: since you get the same session ID from the servers , we can rule out any cookie-related problems. Obviously you successfully create a cookie named a_name
(although I only recommend alphanumeric characters for that cookie name ) on www.example.com
and successfully read that a_name
cookie on forum.example.com
. But as you said, you are not getting any data from forum.example.com
. session.cookie_lifetime = 0
no problem: it means that the cookie remains until the browser is closed .
We need to delve a little further into PHP session handling. The session id you read with session_id()
refers to a file on your server. Typically, this file is present in the /tmp/sess_$session_id
. The content of this file is a $_SESSION
serialized array . (Keep in mind that the data is not serialized in the same way that serialize()
PHP does ... but that doesn't matter right now.)
I think this is a file permissions issue:
-
/tmp/sess_$session_id
the file is installed using user and groupwww.example.com
. -
forum.example.com
tries to open/tmp/sess_$session_id
but does not have the appropriate permissions . - As a result, you get an empty result when you try
print_r($_SESSION);
Solution :
Check the server config file to make sure www.example.com
both forum.example.com
are working as USER AND GROUP ONLY . It is very important! For Apache, find the * .conf file:
User youruser
Group yourgroup
For nginx, find nginx.conf:
user youruser yourgroup;
If changing the server configuration files is not an option, you must ensure that the users working on the two sites are in the same group.
You can verify that this is the problem by first downloading www.example.com
and then sudo ls -ltc sess_*
into your server shell via SSH (look for the sess_
one ending in $session_id
). Then download forum.example.com
and then sudo ls -ltc sess_*
again to see the user and / or group change.
source to share
For this answer, I made several assumptions:
- User must enter credentials at least once in each domain (any other method would be a serious security issue).
- You have access to a database or file space outside of your web root.
- subdomain, domain or any other name will be called "site"
- The goal is to have a common file (physical file or serialized in a database) accessible from every site / domain.
In my example, I will be using a database, since this is the idea I am using, not the database / file access methods, I will have unnecessary rows deleted. IE: How to connect to the database.
If this concept is what you were, or if anyone else wants me to fill in the blanks for completeness, just leave a comment. With code.
I would take a completely different approach.
From what I am gathering from your question and the associated post you linked to, you are trying to share a session using the common session name.
- Each site has its own session ID.
- Each site has its own cookie authenticator ($ _COOKIE ['userid'] or $ _COOKIE ['userhash']).
- Separate sessions are created and a shared cookie is stored on each site.
-
- Using its own session handler, each site reads the same data.
class MySessionHandler implements SessionHandlerInterface
- My after thought was an even simpler approach, a class that acts as a session handler, read / write to a shared file. As the php session handler does not save data until the script ends.
- Using its own session handler, each site reads the same data.
Original idea - won't go into details, this is just for reference.
class MySessionHandler implements SessionHandlerInterface {
private $savePath;
public function read($id) {
$id = some_user_authentication_function();
$hash = $_COOKIE['_h'];
$result = mysql_query("SELECT sess_data FROM login_table WHERE user_id = {$id} AND hash = {$hash}");
return $result['sess_data'];
}
public function write($id, $data) {
$id = some_user_authentication_function();
$hash = $_COOKIE['_h'];
$result = mysql_query("UPDATE login_table SET sess_data = {$data} WHERE user_id = {$id} AND hash = {$hash}");
return ($result === false) ? false : true;
}
}
$handler = new MySessionHandler();
session_set_save_handler($handler, true);
session_start();
class customSessionHandler
{
private $hash;
private $id;
private $sess_db;
public function __construct($db) {
$this->hash = $_COOKIE['hash'];
$this->id = some_user_authentication_function($this->hash);
$this->sess_db = $db;
}
public function get($key) {
$query =
"SELECT value ".
"FROM ".$this->sess_db.
"WHERE user_id = {$id} ".
" AND hash = {$hash} ".
" AND key = {$key}";
$result = mysql_query($query);
return $result['key'];
}
public function set($key, $val) {
$query =
"REPLACE INTO ".$this->sess_db.
"SET {$key} = {$val} ".
"WHERE user_id = {$id} ".
" AND hash = {$hash}";
return (mysql_query($query) === false) ? false : true;
}
}
$handler = new customSessionHandler('sess_data');
session_start();
As stated at the beginning, any code that is not essential to explain the concept has been removed.
Things that may not be obvious to everyone: - $ key and $ val need to be sanitized before being sent to the database. (prevent injection) - The hash is sent to your login functions, so the hash can be used to clean up the session data when needed, can also be used when authenticating the user. - Ready-made mysql statements would be ideal here, so you can prepare two queries in the constructor and then just reuse the statement for each call. Then put the code for closing the connection in the destructor.
After the thought
It would be a lot more secure if every site had its own hash.
Then, if you find a security anomaly, you can simply block or re-request credentials from one site without compromising the hash for the site network.
To implement this would be as simple as creating another table containing: - User ID - site_name (example.com) - Hash - Timeout - Re-authenticate
and by modifying the session_data table, so instead of accessing the $ key => $ val pair with a hash, you access it user_id.
Thanks for reading, I hope it will be helpful to someone.
source to share