Sessões de PHP em subdomínios

92

Estou tentando configurar o seguinte:

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

Se o usuário visitar sub1.example.comou sub2.example.come não estiver conectado, ele será redirecionado para auth.example.come poderá fazer o login.

sub1.example.come sub2.example.comsão dois aplicativos separados, mas usam as mesmas credenciais.

Tentei definir o seguinte no meu php.ini:

session.cookie_domain = ".example.com"

mas não parece estar passando as informações de um domínio para outro.

[Editar]

Tentei o seguinte:

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);

Os IDs de sessão são exatamente os mesmos, mas quando eu despejo a $_SESSIONvariável, ela não mostra as duas chaves, apenas qualquer chave que configurei em cada domínio.

dragonmantank
fonte
Você também deve habilitá-lo em seu código, consulte http://us2.php.net/manual/en/function.session-set-cookie-params.php
Residuum
1
Tenho quase a mesma configuração (defini o domínio do cookie da sessão com uma chamada para "session_set_cookie_params") e funciona bem.
Milen A. Radev
Esta é uma boa função que funciona stackoverflow.com/questions/2835486/…
boksiora

Respostas:

134

Não sei se o problema ainda existe, mas acabei de encontrar o mesmo problema e resolvi definindo um nome de sessão antes de ligar session_set_cookie_params():

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

Não mudei nada no meu, php.inimas agora tudo está funcionando bem.

Jeroen
fonte
10
Confirmo, resolve o problema. Cansei de obter minha resposta lá: stackoverflow.com/questions/4948340/… . Mas eu encontrei aqui.
Romano de
5
Funciona perfeitamente! Estou procurando por isso há séculos. Foi o $some_name = session_name("some_name");que fez isso. Obrigado e voto positivo.
Kit
4
Adicionar session_name("domain");era o ingrediente que faltava para mim também. A documentação no php.net sobre essas configurações de sessão está faltando. Existem postagens da comunidade em php.net que indicam que session.name precisa ser definido antes que as mudanças em session_set_cookie_params () possam ser aplicadas.
David Carroll
3
Sim. confirmado. um bom estava andando em círculos por muito tempo lá;)
Daithí
1
NOTA ... tive que fechar meu navegador e reiniciá-lo para fazê-lo funcionar no servidor de vida. Deixe de fora qualquer ini_set("session.cookie_domain", ".domain.com");causa que estava causando a criação de um novo id de sessão a cada atualização.
Daithí de
24

Uma coisa que pode impedir misteriosamente que os dados da sessão sejam lidos em um subdomínio, apesar dos cookies estarem configurados corretamente, .example.comé o patch Suhosin do PHP. Você pode ter tudo configurado corretamente, conforme os exemplos da pergunta, e pode simplesmente não funcionar.

Desative as seguintes configurações de sessão do Suhosin e você estará de volta aos negócios:

suhosin.session.cryptua = Off 
suhosin.session.cryptdocroot = Off
desenhou
fonte
5

Tente usar:

session.cookie_domain = "example.com"

Ao invés de:

session.cookie_domain = ".example.com"

Observe o período ausente no início.

No entanto, tenha cuidado ao usar isso, porque não é compatível com todos os navegadores.

George Claghorn
fonte
9
Quais navegadores não são compatíveis?
gawpertron
10
que suporte de navegador tem que aqui? esta é uma ação do lado do servidor.
Kuf de
4

Tive exatamente este problema - eu queria que os valores de sessão criados em x.example.local estivessem disponíveis em example.local e vice-versa.

Todas as soluções que encontrei diziam para alterar o domínio da Sessão usando php_value session.cookie_domain .example.local.htaccess (ou via php.ini ou via ini_set).

O problema é que eu estava configurando session.cookie_domainpara todos os subdomínios (até agora ok), mas também para o domínio principal. Definir o session.cookie_domainno domínio principal é aparentemente um não-não.

Basicamente, a forma como funcionou para mim:

  • defina o session.cookie_domainpara TODOS OS SUBDOMÍNIOS.
  • não defina para o DOMAIN principal

Sim, certifique-se de que o domínio tem um TLD (no meu caso .local). O protocolo Http não permite que cookies / sessões sejam armazenados em um domínio sem .tld (ou seja, localhost não funcionará, mas stuff.localhost sim).

EDITAR : Certifique-se também de sempre limpar os cookies do navegador ao testar / depurar sessões em subdomínios. Caso contrário, seu navegador sempre enviará o cookie de sessão antigo, que provavelmente ainda não possui o cookie_domain correto definido. O servidor irá reviver a sessão antiga e, portanto, você obterá resultados falsos negativos. (em muitos posts é mencionado o uso de session_name ('stuff') para o mesmo efeito)

Valentin Florea
fonte
3

Eu resolvi assim

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

Porque eu estava trabalhando no localhost

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

não estava funcionando , ele vê .localhost como o nível superior em vez de .com / .local / ... (suspeito)

xtds
fonte
Também foi corrigido para minha máquina - Ubuntu 14.04
dennis
3

Eu confirmei. a resposta de joreon está correta. Não posso comentar porque minha reputação não é suficiente, então posto meu comentário aqui.

Defina a constante em um arquivo de configuração. Se você quiser alterá-lo, não há necessidade de modificar arquivos inteiros.

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

O nome da sessão não pode conter apenas dígitos, pelo menos uma letra deve estar presente. Caso contrário, um novo id de sessão é gerado a cada vez.

Use o seguinte código para começar a usar a sessão

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

Estou usando esta função:

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
fonte
2

Use-o em cada domínio / subdomínio:

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

O caminho para session.save_pathpode ser diferente para o seu caso, mas deve ser o mesmo em todos os domínios / subdomínios. Nem sempre é verdade por padrão.

Andrii Nemchenko
fonte
1

Use isto, funciona:

ini_set('session.cookie_domain', 
    substr($_SERVER['SERVER_NAME'],strpos($_SERVER['SERVER_NAME'],"."),100));
Ivan
fonte
parece que está definindo o cookie para o tld ... ou estou faltando alguma coisa?
chacham15 de
1

Uso combinado de sessões de cookies de subdomínio e domínio raiz

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

Eu testei trabalhos

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

example.com/sessionview.php // 123

- Códigos

<?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); 
?>
Ilimitada isa
fonte
0

Acho que você não quer algo como OpenID, como Joel está sugerindo, mas quer ter acesso aos dados da sessão em vários domínios.

A única possibilidade que posso pensar como solução para esse problema é armazenar os dados da sessão em um banco de dados e retirá-los desse banco de dados.

Thomas
fonte
Certo, embora a autenticação seja uma parte do que eu quero fazer, também estou interessado nos dados da sessão que são armazenados enquanto o usuário está trabalhando.
dragonmantank
0

Não posso falar por outras versões do PHP, mas em 5.6.6, simplesmente definir o session.cookie_domainvalor no php.iniarquivo fez o truque para permitir que todos os meus subdomínios no iPage compartilhassem o mesmo conjunto de variáveis ​​de sessão.

Certifique-se de remover todos os cookies existentes relacionados ao seu domínio de seu navegador para teste.

session.cookie_domain = '.yourdomainname.example'

Oh, não sei se faz alguma diferença, mas também estou usando o início automático de sessão.

session.auto_start = 1
user3232196
fonte
0

Simplesmente tente usar o seguinte código logo acima do session_start()método

$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
fonte
0

Eu li todas as respostas acima, acho que minha resposta é útil para as pessoas que procuram isso no Google:

  • certifique-se de que os navegadores enviem o cookie da sessão de volta aos servidores (de domínio e subdomínios), defina o domínio do cookie da sessão como .example.com.

  • Certifique-se de que o PHP encontre o "destino" correto para restaurar a variável de sessão:

    • Se o domínio e os subdomínios apontam para a mesma máquina (talvez hosts virtuais diferentes), certifique-se de que session_save_pathé o mesmo para todos (eu testei)
    • Se o domínio e os subdomínios apontam para máquinas diferentes, o armazenamento comum (como banco de dados) é melhor para salvar e restaurar os dados da sessão (ainda não testei). Use session_set_save_handlerpara fazer isso.
usuário953985
fonte
0

Eu sei que isso é antigo, mas funciona bem para mim com vários domínios e subdomínios na mesma caixa.

<?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
fonte
6
Que pergunta você está respondendo? E como isso melhora / melhora nas 9 outras respostas?
random_user_name
0

Usar :

session_name("put_a_session_name");
session_start([
  "cookie_domain" => ".example.com",
  "cookie_path" => "/"
]);
Shakil Ahmmed
fonte
-2

Uma solução rápida e suja é usar isso para o seu redirecionamento:

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

isso adicionará algo ao longo das linhas de ?PHPSESSID=etnm7kbuf5lg0r6tv7je6ehtn4ao URL, que informa ao PHP a id de sessão que deve usar.

Sakabako
fonte
3
Ele também o deixa altamente vulnerável a roubo de sessão :) O problema não é com os IDs de sessão não correspondentes (eles são, veja minha postagem atualizada), mas com os dados não se movendo entre os domínios.
dragonmantank
Concordo, isso é altamente vulnerável, deixando o ID da sessão na string de consulta.
Ian Jamieson
4
Os cookies também são enviados como texto simples, o que não abre caminhos que já não estivessem abertos. Não estou dizendo que é uma boa solução, mas não é menos seguro do que usar cookies.
Sakabako
1
É menos seguro no sentido de que os usuários podem ser (enganados) a compartilhar sua URL e, assim, compartilhar sua ID de sessão ativa. É muito menos provável que um usuário compartilhe seu cookie de ID de sessão involuntariamente.
Bastiaan ten Klooster,