Session Share Across Multiple Domains On Same Server - php

I heard the best method to share session across multiple domains on same server is to use custom php session handler. (ie, domain name different like abc.com, xyz.com but single application.)
But after i tried it, even custom php session handler that using SAME DATABASE ON 1 SERVER can't share session, when i tried to read cookie value from different domain.
Here's my custom session handler, Please kindly check or fix if something missing here. because i've tried it for a week now. can't get it to work
P.S. To get previous session id, i use link such as: newdomain.com/?ssid=[SESSION_ID]
SESSION_INCLUDE.PHP
<?php
// config
$m_host = "localhost"; //MySQL Host
$m_user = "db_user"; //MySQL User
$m_pass = "db_pass"; //MySQL Pass
$m_db = "db_name"; //MySQL Database
$table = "sess_data";
$session_expire = 600; // Session expire time, in seconds (minutes * 60 = seconds)
$gc_probability = 100; // Probability that the garbage collection function will be called. 50% chance by default
ini_set("session.gc_probability",$gc_probability);
/* Open function; Opens/starts session
Opens a connection to the database and stays open until specifically closed
This function is called first and with each page load */
function open ($s,$n) // do not modify function parameters
{
global $session_connection, $m_host, $m_user, $m_pass, $m_db;
$session_connection = mysql_pconnect($m_host,$m_user,$m_pass);
mysql_select_db($m_db,$session_connection);
return true;
}
/* Read function; downloads data from repository to current session
Queries the mysql database, unencrypts data, and returns it.
This function is called after 'open' with each page load. */
function read ($id) // do not modify function parameters
{
global $session_connection,$session_read,$table;
$query = "SELECT data FROM `$table` WHERE id=\"{$id}\"";
$res = mysql_query($query,$session_connection);
if(mysql_num_rows($res) != 1) return ""; // must return string, not 'false'
else
{
$session_read = mysql_fetch_assoc($res);
$session_read["data"] = base64_decode($session_read["data"]);
return $session_read["data"];
}
}
function write ($id,$data) // do not modify function parameters
{
if(!$data) { return false; }
global $session_connection, $session_read, $session_expire, $table;
$expire = time() + $session_expire;
$data = mysql_real_escape_string(base64_encode($data));
if($session_read) $query = "UPDATE `$table` SET data=\"{$data}\", expire=\"{$expire}\" WHERE id=\"{$id}\"";
else $query = "INSERT INTO sess_data SET id=\"{$id}\", data=\"{$data}\", expire=\"{$expire}\"";
mysql_query($query,$session_connection);
return true;
}
function close ()
{
global $session_connection;
mysql_close($session_connection);
return true;
}
function destroy ($id) // do not modify function parameters
{
global $session_connection,$table;
$query = "DELETE FROM `$table` WHERE id=\"{$id}\"";
mysql_query($query,$session_connection);
return true;
}
function gc ($expire)
{
global $session_connection,$table;
$query = "DELETE FROM `$table` WHERE expire < ".time();
mysql_query($query,$session_connection);
}
// Set custom handlers
session_set_save_handler ("open", "close", "read", "write", "destroy", "gc");
// Start session
session_start();
?>
MySQL Database Description
create table sess_data (
id2 int not null auto_increment,
id text not null,
data text,
expire int not null,
primary key(id2)
);

You can't read cookies from one domain in another domain. That's a security thing implemented in the browser. Using a database for sessions allows you to have multiple servers share sessions on the same domain, but does not allow for multiple domains on the same server to share sessions.
If you want to share sessions between domains, you would need to implement some sort of session transfer method when you switch domains. The simplest way to do this would involve passing the session id as a GET parameter from a page on one domain to a page on the other. Then, on the other domain, you would pick up the session id and create a new session using that ID.
While that is a simple way to do it, it isn't very secure and allows for session hijacking. A better way would be to use the database to create a record with the session id in it, set a short timeout on it, and pass the ID of that record to the other domain. The other domain would then pick up the record from the database and create a session with it. If the record in the database is past it's expiration, it wouldn't pick up the session. This would provide better protection against session hijacking.

This is the purpose of session_name(). Assign a different name to each application's session to avoid collisions between $_SESSION keys. The name will be used as the session cookie's name so although both session cookies will be passed to both applications, only the one matching the application's session_name() will be used to populate $_SESSION.
// App 1
session_name('app1');
session_start();
// App 2
session_name('app2');
session_start();

You really should look into SSO (single sign-on). One option for SSO is to use OpenID (as used on SO), and using it will make your life a lot easier.
Here's an article on it : http://devzone.zend.com/article/3581

the cookies and their visibility is a problem. The browser accessing the new site would not send the session id of the old site to the server.
I think your read() does not use the ssid parameter you provide as session id but as the browser has no session with this domain the system generates one with new id as $id. Have a look if $_REQUEST['ssid'] exist in the database.
Custom session handler might a bit big for this job. You could just check if $_REQUEST['ssid'] exist in the session database and rewrite $_SESSION with it.

I was wondering if anyone could give some suggestions on my method for sharing sessions between domains on same server (same cookie storage folder).
In each pages HEAD tag on all my sites, I call the following PHP code
if(!isset($_SESSION['sso'])) {
require_once('database.php');
$sites = array('http://site1', 'http://site2');
session_regenerate_id(); //Make new session id that will be shared
$session_id = session_id();
foreach($sites as $site) {
if($site != CURRENT_SITE) {
$sesh_key = md5(SALT.$site.$session_id);
$database->insertSessionId($sesh_key, $session_id);
$url = sprintf('%s/sso_set.php?k=%s', $site, $sesh_key);
echo('<link type="text/css" rel="stylesheet" href="'.$url.'" />');
}
}
$_SESSION['sso'] = 'SET';
}
Then on each site I have a file called 'sso_set.php' which contains
<?php
session_start();
if(!isset($_SESSION['sso'])) {
require_once('database.php');
$key = $_GET['k'];
$session_id = $database->getSessionId($key);
if($session_id) {
session_destroy();
session_id($session_id);
session_start();
$database->deleteSessionId($key);
$_SESSION['sso'] = 'SET';
}
}
Is using a text/css link a good idea?
I figured this is always called even if Javascript or Images are disabled?
This code basically makes the first site out of all my sites that gets opened by the user sets the Session ID, and then passes it on to the other sites.
Seems to work pretty well.
You get a slight delay the very first time any of the sites opened and the ID is passed to the sites. But, you could do this via AJAX so the page loads fast. But, then you rely on Javascript being enabled.
Thoughts?

Related

How does major website checks for user authentication?

As the title, I ask this question because the only way I know how to check if a user is logged in, is by having on top of each file a session and a query to data base to compared the sessions value.
I have something like this function, then I call this function on top of every php file, this works fine. However I dont think big website such as facebook, youtube and so on has this approach, also this means that all my files have to be .php I cant have .html as I wouldn't be able to run the function below.
public function isSessionValid()
{
session_start();
$dbConfig = new dbconfig("users");
$dbUser = $dbConfig->getDbUser();
$getUser = new GetUser($dbUser);
$result = $getUser->getUser($_SESSION['UN'],$_SESSION['PW'] );
if(!count($result) > 0){
header("Location: ../index.html");
}
}
My question is what are other efficient ways of checking for users credentials?
You don't want to have something like:
$_SESSION['PW']
Plain text unencrypted passwords are a serious concern. You could do something where upon login, you create a access token that is a random hashed string and that gets saved to the users cookies.
Here's an example:
function login()
{
$userName = 'billy';
$password = 'foobar';
// get your user data using username and password.
$userObject = new User();
$userId = $userObject->id;
// create our secure hash.
$accessToken = password_hash($password, PASSWORD_DEFAULT);
// update the user in the row.
mysqli_query($link, "UPDATE users set access_token='$accessToken' WHERE id = $userId");
// expires in 1 day, auto logout.
setcookie('userAccessToken', $accessToken, time() + 86400);
}
function getUser() {
return mysqli_query($link, "SELECT * from users WHERE access_token = ".$_COOKIE['userAccessToken']);
}
Now you only need to check for one attribute which is the access token, and its stored in the cookies in case they come back. Using the hash approach prevents anyone sniffing the cookies and getting private information.
For code maintainability you don't want duplicate code and should always try to create small reusable components that can be used across all your pages. Make a PHP file called auth.php and then just require it in the pages where you need it.
// UserPage.php
require_once __DIR__.'/lib/auth.php';
$user = getUser();
// MessagePage.php
require_once __DIR__.'/lib/auth.php';
$user = getUser();
// lib/auth.php
function getUser() {
return mysqli_query($link, "SELECT * from users WHERE access_token = ".$_COOKIE['userAccessToken']);
}
As a side note, rather than writing your application in plain php and building your own framework, I recommend you checkout laravel.com. They have video tutorials and the framework solves a lot of common problems developers run into, including this one.
One solution would be to configure the webserver to automatically route all requests through isSessionValid() first, then to their actual destination.

Php session data is returning wrong value

I have an application that i built in php 7 with the code-igniter framework and my problem is with the session data , storing and retrieving session data works fine , but occasionally when two people log in at close intervals , the session data for the first user is also retrieved for the second user, searched through the site , saw something similar here (wrong data in PHP session) that suggested that it might be a caching issue (my site uses nginx for caching) , but no concrete solutions were suggested. Any suggestions or Ideas will be appreciated.
Edit : Here is the section of my login library for authentication
public function login_account($email,$password)
{
$db = "db";
$data = array("login_mail" => sha1($email));
$query_result = $this->CI->m_eauth->get_login_password($data,$db);
$hash_password ="";
foreach($query_result->result_array() as $value)
{
$hash_password = $value['hash_password'];
$site_name = $value['hash_name'];
$account_type = $value['account_type'];
$site_match_id = $value['site_match_id'];
$site_levels = $value['levels'];
$site_roles = $value['roles'];
}
if(password_verify($password, $hash_password)){
// Success!
$session_data = array(
"site_id"=>$site_match_id,
"site_email"=>$email,
"site_name"=>$site_name,
"site_avatar"=>md5($email).".jpg",
"site_type"=>$account_type,
"site_levels"=>$site_levels,
"site_roles"=>$site_roles
);
$this->CI->session->set_userdata($session_data);
return "successful";
}
else{
// Invalid credentials
return "unsuccessful";
}
}
Let me add that the login works fine and individual sessions work just fine. But every now and then the problem i described happens , and i'ts quite confusing as i don't know where to look.
There's no real way to sugar coat this, sessions aren't some magical part of PHP that you enable you to just call session_start() and go about your day. If your application is leaking sessions then you haven't secured it properly and you need to fix it.
Session security is a pretty big deal, given that a hijacked session basically gives an attacker total access to someone else's account.
I would recommend you read the official PHP session docs and also consider implementing the Nginx userid module as an additional measure for identifying users.

Ajax - security breach? - PHP

I build a system in php, i have page name x.php
and in this page i create variable name $accountid and get the acocunt id from the sesstion.
now i have others varibles in php at the same page that calls to functions that in other page called functions.php, and deliver the accountid, the function return info about the account (for example the name of the user..)
is this security breach?
i mean the user can call in ajax to the function with other accountid and then he can get info about other account?
here is the code example:
<?php
include "Includs/Config.php";
if(!isset($_SESSION[get("session_name")])) {
header("Location: index.php");
}
$accountid = getAccountid($_SESSION[get("session_name")]);
$e = getECategorys($accountid);
?>
function getE($accountId){
$query = mysql_query("SELECT * FROM `x` WHERE `accountid` = $accountId");
while($result = mysql_fetch_assoc($query)){
// get the info about the account..
}
}
Yes you are right. User can get information by passing another accountId to that function.
Solution: All you can do is check session variable and passed accountId. You can put condition, If session variable (accountId) is matched with passed accountId to that function then only retrieve data otherwise gives an error.
Second solution is to achieve this thing with class base, setting private member variable of accountId.
Hope this helps.
I'm not sure, it seems you are getting accountId from the $_SESSION so this seems to be safe.
Also, users can't call php functions directly using ajax.
Actually, you shouldn't consider AJAX as something else than a simple HTTP request.

Tracking unique visitors only?

Currently I have a file called "hits.php" and on any page I want to track page hits I just use <?php include("hits.php"); ?>
How can I track unique visitors only though? My hits are false since it can be refreshed by the same person and hits go up.
Here's my source:
<?php
$hits = file_get_contents("./client/hits.txt");
$hits = $hits + 1;
$handle = fopen("./client/hits.txt", "w");
fwrite($handle, $hits);
fclose($handle);
print $hits;
?>
I don't really know how I could do cookie checking... is there a way to check IP's? Or what can I do?
Thanks StackO.
The simplest method would be cookie checking.
A better way would be to create an SQL database and assign the IP address as the primary key. Then whenever a user visits, you would insert that IP into the database.
Create a function included on all pages that checks for $_SESSION['logged'] which you can assign whatever 'flag' you want.
If $_SESSION['logged'] returns 'false' then insert their IP address into the MySQL database.
Set $_SESSION['logged'] to 'true' so you don't waste resources logging the IP multiple times.
Note: When creating the MySQL table, assign the IP address' field as the key.
<?php
session_start();
if (!$_SESSION['status']) {
$connection = mysql_connect("localhost", "user", "password");
mysql_select_db("ip_log", $connection);
$ip = $_SERVER['REMOTE_ADDR'];
mysql_query("INSERT INTO `database`.`table` (IP) VALUES ('$ip')");
mysql_close($connection);
$_SESSION['status'] = true;
}
?>
There isn't a perfect solution, but the first two methods (IP address and/or cookies) are the most reliable, and a combination might be even better.
Rather than reinventing the wheel I used an off the shelf solution. For commercial reasons I avoided Google Analytics (I don't want Google to know my web stats - their best interests are not mine). They're probably fine for non-commercial websites, or if you don't use Google for advertising. There are also dozens of alternatives. Eg I use Getclicky.com
At a basic level, you can get the client's IP address by using the PHP $_SERVER['REMOTE_ADDR'] property
Consider setting a cookie or using a session, though this can be defeated by deletion of a cookie or cookie rejection. See the PHP setcookie docs for more info.
There are other methods for browser fingerprinting - check out all the different data you could conceivably use at https://coveryourtracks.eff.org/
How about google analytics if you cant. you could do a database or create another file with the IPs in it, but it could get complicated with a flat file like that.
I found the solution of very poor quality and just a quick and dirty way of doing it.
I too was developing something similar and formulated a quick method which works without redundancy.
I needed a counter for every time someone accessed another user's profile.
Pseudo:
Create a table with viewer's name and viewee's name (daily_views table).
Check to see if exists the viewer's name with the viewee's name (on the same row).
If they do not exist, update user counter +1 (in users table).
Else do nothing.
Reset entire table values null every 24/12 hours via cron job.
This will deny the same person accessing the same user profile to add 1 to the
counter on refresh for the whole day (or 12 hours) whereas the above solution
by Glenn Nelson would indeed add 1 to the counter, but deny adding to every
user's counter at the same time.
Not only this, but if you were to logoff and log back in to the website, then
it would simply re-add to the counter in which some cases trolls and haxorz
wannabe's will exploit this (as the session is destroyed and started again).
Here are my sample tables:
users
{
user_id INT(8) auto increment, user_name varchar(32), user_counter INT(12)
};
daily_views
{
view_id INT(8) auto increment, viewer_name VARCHAR(32), viewee_name VARCHAR(32)
};
Here is sample code I've written:
<?php
session_start();
$uname = $_SESSION['username'];
$vieweepage = $_GET['name']; //gets the name of the persons page/profile via previous page/form
$connect = mysql_connect("localhost","user","password") or die("Couldn't connect; check your mysql_connect() settings");
$database = mysql_select_db("database") or die("Could not locate database!");
$query = mysql_query("SELECT user_counter from users");
$query = mysql_fetch_row($query);
$counter = $query[0];
$viewcheck = mysql_query("SELECT viewer_name from daily_views WHERE viewee_name='$vieweepage'");
$viewrow = mysql_num_rows($viewcheck);
$newcounter = $counter + 1;
if($viewrow == 0)
{
$update = mysql_query("UPDATE users SET user_counter='$newcounter' WHERE user_name='$vieweepage'");
$insert = mysql_query("INSERT into daily_views (viewer_name, viewee_name) VALUES ('$uname', '$vieweepage')");
}
?>
currently i am using remote address and session ID for visitor.i think its valid visitor because a single user can visit no of times in a days and counter not depends on refresh its only depends on new session.
You could save a timestamp to localStoage in javascript. LocalStoage isn't removed by the browser, so you should be save to check against that. I know that it isn't serverside checking, but it may be helpful anyway.

Handling Sessions

Need some help with how to handle sessions. I am using ajax techniques to implement a group discussion platform and alot of its success depends on whether or not i can handle sessions properly, be able to see who is online etc. How can i do this efficiently. Remember, this is a typical single url ajax application where the server only responds to request. All of the form validation is done on the client side as the user enters his data. I need help with this. Below what have written so far.
<?php
include_once "../database/dbconnect.php";
session_start();
$username = isset($_POST["userNameLogin"]) ? $_POST["userNameLogin"] : $_SESSION["userNameLogin"];
$pwd = isset($_POST["passwordLogin"]) ? $_POST["passwordLogin"] : $_SESSION["passwordLogin"];
// Sending these messages to my client side validation code json-style.
if(!isset($username)){
echo("{message : 'NoName'}");
}
elseif(!isset($pwd)){
echo("{message : 'NoPW'}");
}
// creating the session variables to hold username and pwd
$_SESSION['userNameLogin'] = $username;
$_SESSION['passwordLogin'] = $pwd;
// calling the function incuded above to make connection to mysql db
dbConnection();
//query retrieves username and pwd from db and counts the result. if it is one, then they //certianly exist and if not unset the variables created above. The varibles were created
//above so i do not have to check if they exist before unsetting them.
$sQuery = "SELECT * FROM users WHERE
username = '$username' AND password = '$pwd'";
$result = mysql_query($sQuery) or die(mysql_error());
$intFound = mysql_num_rows($result);
if ($intFound == 0) {
unset($_SESSION['userNameLogin']);
unset($_SESSION['passwordLogin']);
// AD - Access Denied
echo("{message : 'AD'}");
}
else{
//a flag to set in the database who is currently online. value of 1 for users who are //online and zero for users who are not. If i want a list of those online, i check the //column called online and then check to see if the $_SESSION['username'] exist. If it //does then i know the user is online. That is what the second script is for. New to this //stuff, and do not know a better way of doing it
mysql_query("UPDATE users SET online = '1' WHERE username = '$username'") or die(mysql_error);
}
The above script should let the user login or deny access by sending messages to the validation code on client side.
As you can see, i am new to this stuff i having my share of problems. What can i do to make sure that sessions are set and unset properly i.e when user logs out.
secondly how can i monitor who is online and who is not using sessions. This is how i am trying to check who is currently online and then building a json file with the user names and sending it to the client. Json is easier to parse.
The script below tries to determine who is online
<?php
// this script determines which sessions are currently active by
// 1.) checking to see which online fields in the users table are set to 1
// 2.) by determining if a session variable has been set for these users.
// If it is not set, it means user is no longer active and script sets its online field in the users table to zero.
// After doing this, the script, then queries the users table for online fields with values one, writes them to an
// array and passes them to the client.
include_once "../database/dbconnect.php";
//include "../validation/accessControl.php";
$tempActiveUsers = array();
$activeUsers = array();
$nonActiveUsers = array();
dbConnection();
$sql = "SELECT username from users WHERE online = '1' ";
$active_result = mysql_query($sql) or die(mysql_error);
if($active_result){
while($aValues = mysql_fetch_array($active_result)){
array_push($tempActiveUsers, $aValues['username']);
}
}
forEach($tempActiveUsers as $value){
/*if($_SESSION['$value'] == $value){
$activeUsers += $value;
} */
if(isset($_SESSION['userNameLogin']) == $value){
array_push($activeUsers, $value);
}else{
array_push($nonActiveUsers, $value);
}
}
forEach($nonActiveUsers as $value1){
$sql1 = "UPDATE users SET online='0' WHERE username = '$value1'";
$set_result = mysql_query($sql1) or die(mysql_error);
}
$length = sizeof($activeUsers);
$len = 1;
$json ='{"users" : {';
$json .= '"user":[';
forEach($activeUsers as $value2){
$json .= '{';
$json .= '"username" : "' .$value2.'" }';
if($len != $length){
$json .= ',';
}
$len++;
}
$json .= ']';
$json .= '}}';
echo $json;
Please look through and give some advice. Will appreciate that very much. My project framework is up and good, but i can implement much user functionality yet because i cann't track who is online and how to manage thier sessions. If you need more background info let me know. Thanks in advance
Add 'Log out' button and click event handler on it which makes an ajax request to server to stop session by unsetting session vars or destroying session completely, and on ajax completion callback put a function to update user interface to show user is logged out.
Log in procedure can be done as follows: user clicks 'Log in' button and some form asking for user name and password appears. Then submit this form with ajax to a server script like your first one. Server script checks whether user name and password are valid and returns authentication information to a client via callback: failure notice upon failed login or some information about user currently logged in, e.g. user name, fullname and anything you might need about this user on client side in js. Then your client script proceeds according to login status returned from server-side script.
You should always remember about security.
Before sending any sensitive data to a client side with json, you shoud always check if session is valid and started. Client-side scripts could be easily modified and executed without your control and you should prevent undesired activity only on server side.
You should apply some escaping on user-POSTed fields before using them in sql queries to avoid sql injection attacks, e.g. by using mysql_escape_string().
And instead of building json strings, you can use json_encode() which works good for primitives, objects and arrays, you'll save some time.

Categories