Sesje PHP w subdomenach

92

Próbuję skonfigurować następujące elementy:

auth.example.com
sub1.example.com
sub2.example.com

Jeśli użytkownik odwiedza witrynę sub1.example.comlub sub2.example.comnie jest zalogowany, zostaje przekierowany auth.example.comi może się zalogować.

sub1.example.comi sub2.example.comsą to dwie oddzielne aplikacje, ale używają tych samych poświadczeń.

Próbowałem ustawić następujące w moim php.ini:

session.cookie_domain = ".example.com"

ale wydaje się, że nie przekazuje informacji z jednej domeny do drugiej.

[Edytować]

Próbowałem następujących rzeczy:

sub1.example.com/test.php

session_set_cookie_params(0, '/', '.example.com');
session_start();
print session_id() . "<br>";
$_SESSION['Regsitered'] = 1;
echo '<a href="http://auth.example.com/test.php">Change Sites</a>'

auth.example.com/test.php

session_set_cookie_params(0, '/', '.example.com');
session_start();
print session_id() . "<br>";
$_SESSION['Checked'] = 1;
print_r($_SESSION);

Identyfikatory sesji są dokładnie takie same, ale kiedy zrzucam $_SESSIONzmienną, nie pokazuje ona obu kluczy, tylko ten, który ustawiłem w każdej domenie.

Dragonmantank
źródło
Musisz również włączyć to w swoim kodzie, patrz http://us2.php.net/manual/en/function.session-set-cookie-params.php
Residuum
1
Mam prawie taką samą konfigurację (ustawiłem domenę cookie sesji za pomocą wywołania „session_set_cookie_params”) i działa dobrze.
Milen A. Radev
Oto fajna funkcja, która działa stackoverflow.com/questions/2835486/ ...
boksiora

Odpowiedzi:

134

Nie wiem, czy problem nadal istnieje, ale właśnie napotkałem ten sam problem i rozwiązałem go ustawiając nazwę sesji przed wywołaniem session_set_cookie_params():

$some_name = session_name("some_name");
session_set_cookie_params(0, '/', '.example.com');
session_start();

Nic nie zmieniłem w moim, php.iniale teraz wszystko działa dobrze.

jeroen
źródło
10
Potwierdzam, to rozwiązuje problem. Zmęczyłem się, aby uzyskać tam odpowiedź: stackoverflow.com/questions/4948340/… . Ale znalazłem to tutaj.
Roman
5
Działa idealnie! Szukałem tego od wieków. To on $some_name = session_name("some_name");to zrobił. Dziękuję i zagłosuj.
Kit
4
Dodanie również session_name("domain");było dla mnie brakującym składnikiem. Brakuje dokumentacji na php.net dotyczącej tych ustawień sesji. Istnieją posty społeczności na php.net, które wskazują, że nazwa session.name musi zostać zdefiniowana przed zastosowaniem zmian w session_set_cookie_params ().
David Carroll,
3
tak. Potwierdzony. fajny
krążył
1
UWAGA ... musiałem zamknąć przeglądarkę i uruchomić ją ponownie, aby działała na serwerze życia. Pomiń każdą ini_set("session.cookie_domain", ".domain.com");przyczynę, która powodowała, że ​​tworzył nowy identyfikator sesji przy każdym odświeżaniu.
Daithí
24

Jedną z rzeczy, która może w tajemniczy sposób uniemożliwić odczyt danych sesji z subdomeny, pomimo poprawnego ustawienia plików cookie, .example.comjest łatka PHP Suhosin. Możesz mieć wszystko poprawnie skonfigurowane, jak na przykładach w pytaniu, i po prostu może nie działać.

Wyłącz następujące ustawienia sesji Suhosin i wrócisz do pracy:

suhosin.session.cryptua = Off 
suhosin.session.cryptdocroot = Off
drewm
źródło
5

Spróbuj użyć:

session.cookie_domain = "example.com"

Zamiast:

session.cookie_domain = ".example.com"

Zwróć uwagę na brakujący okres na początku.

Uważaj jednak, ponieważ nie jest obsługiwany przez wszystkie przeglądarki.

George Claghorn
źródło
9
Które przeglądarki nie są obsługiwane?
gawpertron
10
jakie wsparcie przeglądarki musi tutaj zrobić? jest to akcja po stronie serwera.
Kuf
4

Miałem dokładnie ten problem - chciałem, aby wartości sesji utworzone na x.example.local były dostępne na example.local i na odwrót.

Wszystkie rozwiązania, które znalazłem, mówiły, że zmieniają domenę sesji za pomocą php_value session.cookie_domain .example.local.htaccess (lub przez php.ini lub przez ini_set).

Problem polegał na tym, że ustawiałem session.cookie_domaindla wszystkich subdomen (do tej pory ok), ale także dla domeny głównej. Ustawienie session.cookie_domainna domenie głównej najwyraźniej nie jest możliwe.

Zasadniczo sposób, w jaki to zadziałało dla mnie:

  • ustaw session.cookie_domaindla WSZYSTKICH PODDOMEN.
  • nie ustawiaj go dla głównej DOMENY

O tak, upewnij się, że domena ma domenę TLD (w moim przypadku .local). Protokół HTTP nie pozwala na przechowywanie plików cookie / sesji w domenie bez .tld (tzn. Localhost nie będzie działać, ale stuff.localhost tak).

EDYTUJ : Upewnij się również, że zawsze usuwasz pliki cookie przeglądarki podczas testowania / debugowania sesji w subdomenach. Jeśli tego nie zrobisz, Twoja przeglądarka zawsze będzie wysyłać stary plik cookie sesji, który prawdopodobnie nie ma jeszcze ustawionego prawidłowego pliku cookie_domain. Serwer ożywi starą sesję i uzyskasz fałszywie negatywne wyniki. (w wielu postach jest mowa o używaniu session_name ('stuff') dla dokładnie tego samego efektu)

Valentin Florea
źródło
3

Rozwiązałem to w ten sposób

ini_set('session.cookie_domain', '.testdomain.example');
session_start();

Ponieważ pracowałem na localhost

ini_set('session.cookie_domain', '.localhost');

nie działał , widzi .localhost jako najwyższy poziom zamiast .com / .local / ... (podejrzewam)

xtds
źródło
Naprawiono to również dla mojej maszyny - Ubuntu 14.04
dennis
3

Potwierdziłem. Odpowiedź joreona jest prawidłowa. Nie mogę komentować, ponieważ moja reputacja nie wystarczy, więc zamieszczam tutaj komentarz.

Zdefiniuj stałą w pliku konfiguracyjnym. Jeśli chcesz to zmienić, nie musisz modyfikować całych plików.

define('ROOT_DOMAIN',   'mysite.example');
define('PHP_SESSION_NAME', 'MYSITE'); 

Nazwa sesji nie może składać się tylko z cyfr, musi być obecna przynajmniej jedna litera. W przeciwnym razie za każdym razem generowany jest nowy identyfikator sesji.

Użyj poniższego kodu, aby rozpocząć korzystanie z sesji

session_name(PHP_SESSION_NAME);
session_set_cookie_params(0, '/', '.' . ROOT_DOMAIN);
session_start();

Używam tej funkcji:

function load_session() {
    if (session_status() == PHP_SESSION_NONE) {
        session_name(PHP_SESSION_NAME);
        session_set_cookie_params(0, '/', '.' . ROOT_DOMAIN);
        session_start();
    } elseif (session_name() != PHP_SESSION_NAME) {
        session_destroy();
        session_name(PHP_SESSION_NAME);
        session_set_cookie_params(0, '/', '.' . ROOT_DOMAIN);
        session_start();
    }
}
load_session(); // put it in anywhere you want to use session
Terry Lin
źródło
2

Używaj go w każdej domenie / subdomenie:

session_name('name');
ini_set('session.cookie_domain', '.example.com');
ini_set('session.save_path', '/var/lib/php/session');
session_start();

Ścieżka do session.save_pathmoże być inna w Twoim przypadku, ale powinna być taka sama w każdej domenie / subdomenie. Nie zawsze jest to prawda.

Andrii Nemchenko
źródło
1

Użyj tego, to działa:

ini_set('session.cookie_domain', 
    substr($_SERVER['SERVER_NAME'],strpos($_SERVER['SERVER_NAME'],"."),100));
Ivan
źródło
wygląda na to, że ustawia plik cookie dla tld ... czy czegoś mi brakuje?
chacham15
1

Łączone użycie sesji plików cookie domeny podrzędnej i domeny głównej

Ratunek: http://php.net//manual/tr/function.session-set-cookie-params.php

Sprawdziłem działa

sub.example.com/sessionadd.php?id=123

example.com/sessionview.php // 123

- Kody

<?php 
$currentCookieParams = session_get_cookie_params(); 

$rootDomain = '.example.com'; 

session_set_cookie_params( 
    $currentCookieParams["lifetime"], 
    $currentCookieParams["path"], 
    $rootDomain, 
    $currentCookieParams["secure"], 
    $currentCookieParams["httponly"] 
); 

session_name('mysessionname'); 
session_start(); 

setcookie($cookieName, $cookieValue, time() + 3600, '/', $rootDomain); 
?>
Nieograniczone isa
źródło
0

Wydaje mi się, że nie chcesz czegoś takiego jak OpenID, jak sugeruje Joel, ale chcesz mieć dostęp do danych sesji w wielu domenach.

Jedyną możliwością, którą mogę sobie wyobrazić jako rozwiązanie tego problemu, jest przechowywanie danych sesji w bazie danych i wyciąganie ich z tej bazy danych.

Tomasz
źródło
Racja, chociaż uwierzytelnianie jest częścią tego, co chcę zrobić, interesują mnie również dane sesji, które są przechowywane podczas pracy użytkownika.
dragonmantank
0

Nie mogę wypowiadać się na temat innych wersji PHP, ale w 5.6.6 samo ustawienie session.cookie_domainwartości w php.inipliku załatwiło sprawę, pozwalając wszystkim moim subdomenom na iPage współdzielić ten sam zestaw zmiennych sesji.

Pamiętaj, aby usunąć wszystkie istniejące pliki cookie związane z Twoją domeną z przeglądarki, aby przetestować.

session.cookie_domain = '.yourdomainname.example'

Och, nie wiem, czy to robi jakąkolwiek różnicę, ale używam też autostartu sesji.

session.auto_start = 1
user3232196
źródło
0

Po prostu spróbuj użyć następującego kodu powyżej session_start()metody

$sess_life_time = 21600; //in seconds
$sess_path = "/";
$sess_domain = ".example.com";
$sess_secure = true; // if you have secured session
$sess_httponly = true; // httponly flag

session_set_cookie_params($sess_life_time, $sess_path, $sess_domain, $sess_secure, $sess_httponly);
mohsin.mr
źródło
0

Przeczytałem wszystkie powyższe odpowiedzi, myślę, że moja odpowiedź jest pomocna dla osób szukających tego w Google:

  • upewnij się, że przeglądarki wysyłają plik cookie sesji z powrotem do serwerów (domeny i subdomen), ustaw domenę plików cookie sesji jako .example.com.

  • Upewnij się, że PHP znajduje właściwy „cel”, aby przywrócić zmienną sesji:

    • Jeśli domena i subdomeny wskazują na tę samą maszynę (być może różne wirtualne hosty), upewnij się session_save_path jest taka sama dla wszystkich (testowałem)
    • Jeśli domena i subdomeny wskazują różne maszyny, wspólny magazyn (taki jak baza danych) jest najlepszy do zapisywania i przywracania danych sesji (jeszcze nie testowałem). Użyj session_set_save_handlerdo tego.
user953985
źródło
0

Wiem, że to jest stare, ale działa dobrze w przypadku wielu domen i subdomen w tym samym pudełku.

<?php
define('site_domain','example.com');
session_set_save_handler('_open',
                         '_close',
                         '_read',
                         '_write',
                         '_destroy',
                         '_clean');

function _open(){

    global $_sess_db;

$db_user = 'user';
$db_pass = 'pass';
$db_host = 'localhost';

if ($_sess_db = mysql_connect($db_host, $db_user, $db_pass)){

    return mysql_select_db('database', $_sess_db);

}

return false;

}

function _close(){

    global $_sess_db;
    return mysql_close($_sess_db);

}

function _read($id){

    global $_sess_db;
    $id = mysql_real_escape_string($id);
    $domain = mysql_real_escape_string(site_domain);
    $agent = mysql_real_escape_string(isset($_SERVER['HTTP_USER_AGENT']));

    $sql = "SELECT data
    FROM sessions
    WHERE id = '$id' AND domain = '$domain' AND agent = '$agent'";

     if ($result = mysql_query($sql, $_sess_db)){

         if (mysql_num_rows($result)){
             $record = mysql_fetch_assoc($result);
             return $record['data'];
        }

    }

    return '';

}

function _write($id, $data){

    global $_sess_db;
    $access = time();

    $id = mysql_real_escape_string($id);
    $access = mysql_real_escape_string($access);
    $data = mysql_real_escape_string($data);
    $domain = mysql_real_escape_string(site_domain);
    $agent = mysql_real_escape_string(isset($_SERVER['HTTP_USER_AGENT']));

    $sql = "REPLACE INTO sessions
    VALUES ('$id', '$access', '$data', '$domain', '$agent')";

    return mysql_query($sql, $_sess_db);

}

function _destroy($id){

    global $_sess_db;
    $id = mysql_real_escape_string($id);
    $domain = mysql_real_escape_string(site_domain);
    $agent = mysql_real_escape_string(isset($_SERVER['HTTP_USER_AGENT']));

    $sql = "DELETE FROM sessions
    WHERE id = '$id' AND domain = '$domain' AND agent = '$agent'";

    return mysql_query($sql, $_sess_db);

}

function _clean($max){

    global $_sess_db;
    $old = time() - $max;
    $old = mysql_real_escape_string($old);
    $domain = mysql_real_escape_string(site_domain);
    $agent = mysql_real_escape_string(isset($_SERVER['HTTP_USER_AGENT']));

    $sql = "DELETE FROM sessions
    WHERE  access < '$old' AND domain = '$domain' AND agent = '$agent'";

    return mysql_query($sql, $_sess_db);

}

?>

Ian
źródło
6
Na jakie pytanie odpowiadasz? I jak to poprawia / wzmacnia 9 innych odpowiedzi?
random_user_name
0

Posługiwać się :

session_name("put_a_session_name");
session_start([
  "cookie_domain" => ".example.com",
  "cookie_path" => "/"
]);
Shakil Ahmmed
źródło
-2

Szybkim i brudnym rozwiązaniem jest użycie tego do przekierowania:

header( $url.'?'.session_name().'='.session_id() );

doda to ?PHPSESSID=etnm7kbuf5lg0r6tv7je6ehtn4do adresu URL coś , co informuje PHP o identyfikatorze sesji, którego powinien użyć.

sakabako
źródło
3
To także czyni go wysoce podatnym na kradzież sesji :) Problem nie polega na tym, że identyfikatory sesji nie pasują (są, zobacz mój zaktualizowany post), ale z danymi nie przemieszczającymi się między domenami.
dragonmantank
Zgoda, jest to wysoce podatne na pozostawienie identyfikatora sesji w ciągu zapytania.
Ian Jamieson
4
Pliki cookie są również wysyłane jako zwykły tekst, co nie otwiera żadnych ścieżek, które nie były jeszcze otwarte. Nie twierdzę, że to dobre rozwiązanie, ale jest nie mniej bezpieczne niż używanie plików cookie.
sakabako
1
Jest mniej bezpieczny w tym sensie, że użytkownicy mogą (oszukiwać) udostępniać swój adres URL, a tym samym udostępniać swój identyfikator aktywnej sesji. Jest znacznie mniej prawdopodobne, że użytkownik niechcący udostępni plik cookie z identyfikatorem sesji.
Bastiaan ten Klooster