Сессия потеряна при переключении с HTTP на HTTPS в PHP

При отправке пользователя на страницу оформления заказа он переключается с http://sitename.com на https://sitename.com.

В результате $_SESSION переменных теряются.

На сайте есть действующий SSL-сертификат, который может быть полезен, а может и нет.


person Allan    schedule 14.01.2009    source источник
comment
Какой браузер вы используете? Задействованы ли какие-либо поддомены, например www.? Можете ли вы воспроизвести проблему в другом месте?   -  person Unsigned    schedule 17.11.2011


Ответы (16)


Когда вы переключаетесь между службами HTTP и HTTPS на одном сервере, ваш идентификатор сеанса HTTP не передается в сеанс HTTPS. Вы можете установить его, передав идентификатор сеанса со страницы HTTP на страницу HTTPS одним из трех возможных способов:

Из PHP: session_start:

session_start() создает сеанс или возобновляет текущий на основе текущего идентификатора сеанса, который передается через запрос, например GET, POST или файл cookie.

Когда вы используете сеансы, вы обычно начинаете свой сценарий с session_start(). Если в браузере установлен файл cookie идентификатора сеанса, session_start() будет использовать этот идентификатор сеанса. Если в браузере не установлен файл cookie идентификатора сеанса, session_start() создаст новый.

Если идентификатор сеанса не установлен (в вашем примере браузер создает новый файл cookie идентификатора сеанса для сеанса HTTPS), вы можете установить его с помощью функции session_id(). session_id() также удобно возвращает идентификатор сеанса в виде строки. Так

...

$currentSessionID = session_id();

...

устанавливает переменную $currentSessionID равной текущему идентификатору сеанса, и

...

session_id($aSessionID);

...

устанавливает файл cookie sessionID в браузере на $aSessionID. из PHP: session_id

Вот пример с двумя скриптами. Доступ к одному из них осуществляется через HTTP, а к другому — через HTTPS. Они должны находиться на одном сервере для хранения данных сеанса.

Сценарий 1 (HTTP):

<?php

// This script will create a session and display a link to your secure server address
// to transfer your session ID. In this example, the secure page to receive the session
// ID is located at http://www.yoursite.com/safePages/securePage.php

// Start a session using the current session ID stored in a cookie, or create
// a new session if none is set.
session_start();

$currentSessionID = session_id();

// Set a variable that will be retrieved with the HTTPS script.
$_SESSION['testvariable'] = 'It worked';

// $secureServerDomain is the domain of your secure server
$secureServerDomain = 'www.yoursite.com';

// $securePagePath is the path to the page that will receive and set the session ID.
$securePagePath = '/safePages/securePage.php'

echo '<a href="https://' . $secureServerDomain . $securePagePath . '?session="' . $currentSessionID . '">Click here to transfer your session to the secure server</a>';

?>

Сценарий 2 (HTTPS):

<?php

// Retrieve the session ID as passed via the GET method.
$currentSessionID = $_GET['session'];

// Set a cookie for the session ID.
session_id($currentSessionID);

// Start a session.
session_start();

// Test retrieval of variable set when using HTTP.
if (!empty($_SESSION['testvariable'])) {
      echo $_SESSION['testvariable'];
} else {
      echo 'It did not work.';
}

?>

Чтобы это работало, серверы HTTP и HTTPS должны использовать одну и ту же подложку для хранения данных сеанса (т. е. для обработчика файлов по умолчанию запускать на одной физической машине с одним и тем же php.ini). Здесь есть некоторые недостатки безопасности, поэтому я бы не стал использовать этот код для передачи конфиденциальной информации. Это просто рабочий пример.

Когда я сталкивался с этой проблемой раньше, я придумал это как быстрое решение, но я просто вспомнил первоначальную причину проблемы. Я переходил с http://www.example.com/page.php на https://example.com/page.php (обратите внимание на отсутствие "www"). Убедитесь, что http://www.example.com/page.php будет ссылаться на https://www.example.com/page.php и http://example.com будет ссылаться на https://example.com/page.php.

PS, на самом деле я не запускал эти скрипты, поэтому может быть одна или две опечатки, из-за которых они не работают должным образом.

person Jacob    schedule 14.01.2009
comment
Использование дополнительно соленого хэша защитит эту процедуру. - person Gumbo; 14.01.2009
comment
Я не вижу здесь природы проблем с безопасностью — знаете какие-нибудь ресурсы, которые их описывают? - person bcoughlan; 09.07.2010
comment
Контрольный вопрос: кто-то может постоянно заходить на ваш сайт и угадывать переменные session_id, в конечном итоге перехватывая чужой сеанс. Я не понимаю, как будет работать соленый хеш, так как это односторонняя операция; вы бы посолили пароль и сделали то же самое для попытки ввода пароля, но в этом случае это не совсем сработает; вам нужно исходное значение. - person Dean J; 20.03.2011
comment
@DeanJ - вы генерируете контрольную сумму на стороне сервера и анализируете ее по URL-адресу в качестве параметра. Например, вы можете сгенерировать хэш вида: $hash = md5($currentSessionID.'somesecretsalt'), а затем URL-адрес должен выглядеть так: ?session='.$currentSessionID.'&hash='.$hash. Затем на целевом сайте вы должны проверить, соответствует ли md5($_GET['session'].'somesecretsalt') == $_GET['hash']. Таким образом, вы можете сказать, что session_id не был просто создан. Идентификатор сеанса ДОЛЖЕН соответствовать хэшу, сгенерированному сервером (который практически невозможно взломать при использовании длинного солт-значения). - person Trolley; 27.03.2013
comment
+1 за то, что заметили проблему перехода с example.com/page.php на example.com/page.php - это тоже было проблемой для меня. Я решил эту проблему, изменив файл .htaccess, чтобы полностью предотвратить www: RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC] RewriteRule ^.*$ example.com%{REQUEST_URI} [R=301,L] - person JSP64; 13.06.2014
comment
Не могли бы вы также использовать один и тот же метод для двух веб-сайтов на другом порту, например. mywebsite.com и mywebsite.com:80/index.html ? - person StackOverQuestions; 12.01.2015

Похоже, файл cookie сеанса настроен на безопасность. Файлы cookie имеют флаг "secure", который, если установлено значение true, означает, что файл cookie не будет отправлен на сайты, не использующие https. PHP, вероятно, использует это для своих сеансовых файлов cookie. Вы можете изменить это с помощью функции session_set_cookie_params или с помощью session.cookie_secure в php.ini.

person JW.    schedule 14.01.2009
comment
ОП указал, что файл cookie был потерян при передаче на зашифрованное соединение. Флаг secure здесь не применяется. - person Unsigned; 17.11.2011
comment
@Unsigned — если вы переключитесь на безопасную страницу и скажете странице использовать только файлы cookie безопасного сеанса, она должна создать новый безопасный файл cookie и не сможет использовать существующий незащищенный. - person martinstoeckli; 17.11.2011
comment
@martinstoeckli - Верно. Однако значение по умолчанию — off. Если бы это было on, файлы cookie не были бы отправлены на страницу HTTP, а это означает, что файл cookie никогда не должен был существовать там. Следовательно, файл cookie не является безопасным. - person Unsigned; 17.11.2011
comment
@JW был прав, мне потребовалось некоторое время, чтобы понять, 'session_start (); setcookie(session_name(), session_id(), NULL, NULL, NULL, 0);' устанавливает cookie как для http, так и для https, предотвращая потерю сеанса. - person ontananza; 09.08.2012

У нас тоже была эта проблема. Оказалось, что мы использовали патч suhosin в нашей установке PHP. Исправляем, установив suhosin.session.cryptdocroot = Off в /etc/php.d/suhosin.ini.

Руководство по сухосину о suhosin.session.cryptdocroot см. на http://www.hardened-php.net/suhosin/configuration.html#suhosin.session.cryptdocroot.

Первоначально мы нашли исправление в этом сообщении в блоге: http://www.yireo.com/blog/general-news/315-switch-between-http-and-https-looses-php-session.

person Tom    schedule 16.07.2010
comment
Мне также нужно было отключить suhosin.cookie.cryptdocroot. - person mrwalker; 23.09.2011

В следующем решении предполагается, что безопасный и незащищенный серверы имеют доступ к одним и тем же внутренним службам (кешу, хранилищу базы данных и т. д.).

Нам пришлось столкнуться с той же проблемой при отправке пользователя в наш процесс оформления заказа, когда он сделал покупки. Чтобы решить эту проблему, мы создали слой кэширования и кэшировали все соответствующие данные. Например, мы могли бы получить идентификаторы продукта и идентификатор пользователя из значений сеанса, сериализовать их, создать хэш и, наконец, сохранить данные сеанса в кеше, используя хэш в качестве ключа. Затем мы перенаправим пользователя на безопасный сайт с хешем в URL-адресе.

Когда пользователь оказывался на защищенном сайте, мы пытались извлечь данные из кеша на основе хеша. Затем с идентификатором пользователя и идентификатором продукта мы могли бы загрузить все данные о ценах и описаниях из базы данных и предоставить пользователю для окончательного просмотра при оформлении заказа.

Существует риск наследования в том, что данные кеша нестабильны, но у нас никогда не было проблем с этим, поскольку перенаправление происходит быстро.

person Mike Purcell    schedule 15.11.2011
comment
наши решения похожи с одним отличием. Я предложил хранить в базе данных, а вы имели в виду кеш. как он может создать общую память для использования между разными сеансами? - person Uğur Gümüşhan; 16.11.2011
comment
@UğurGümüşhan: Хорошо. Решение для базы данных будет медленнее по сравнению с кешем (по отношению к трафику), но будет постоянным. Как уже упоминалось в моем посте, мы используем хэш, который мы генерируем на стороне отправки (без ssl), для поиска данных на стороне приема (ssl). - person Mike Purcell; 16.11.2011
comment
Чем это отличается от отправки идентификатора сеанса в URL-адресе (как упоминалось в других ответах)? Помимо того, что хэш, возможно, длиннее и его труднее угадать? - person MrWhite; 05.04.2013
comment
@w3d: Не уверен, что ты имеешь в виду. Вы можете использовать идентификатор сеанса, если хотите, или любую комбинацию символов. Дело в том, что вы кэшируете данные сеанса с одной стороны и перенаправляете пользователя с помощью ключа поиска на другую сторону, поэтому вы можете создать новый сеанс с данными старого сеанса. - person Mike Purcell; 05.04.2013

Похоже, ваш файл cookie сеанса создан с безопасным флагом, но есть что-то с URL-адресом вашей страницы оформления заказа, из-за которого файл cookie сеанса не передается.

Или, возможно, ваш файл cookie сеанса не является безопасным - просто URL-адрес страницы оформления заказа достаточно отличается (http://mysite.com против http://www.mysite.com), что браузер не отправляет файл cookie.

Если вы хотите узнать больше о переключении с http на https и наоборот, взгляните на в моем отзыве о селективном ssl :-)

person Community    schedule 26.02.2009

Вы не можете передавать значения сеанса между разными доменами. Вы должны использовать http post-get или базу данных для передачи ваших значений. В целях безопасности вы можете объединить все свои значения в строку и использовать

sha1($string)

и опубликуйте его вместе со своими значениями и рассчитайте sha1 для значений, которые получает другая страница, а затем сравните хэши.

Метод Post в разных доменах заставляет браузеры отображать сообщение безопасности, поэтому не используйте его.

Использование URL-адреса для метода get небезопасно, вам нужно будет запросить пароль на перенаправленной странице, чтобы разрешить получение параметров в вашей системе.

Не используйте файлы cookie, если вам нужна безопасность.

Я предлагаю сохранить значения в базе данных и сгенерировать ключ, затем сделать ссылку перенаправления с помощью вашего ключа, перенаправить страницу пользователей с параметром get, который имеет ключ, затем пользователь страницы перенаправляется на получение этого ключа , извлекает данные и удаляет ключ. вы можете сгенерировать ключ с помощью sha1

PAGE 1---
$key=sha1($allvalsconcat);
//insert your session values to a database also the key in a column
header("Location: page2.php?key=".$key);

PAGE 2---
// select from database where key=$_GET["key"];
// delete from table where key=$key

это довольно безопасно.

что может случиться: скрипт, вводящий случайные значения для параметра «ключ», чтобы ваш сайт загружал данные в вашу память?

Этого не произойдет, потому что вы удалите запись после ее использования. Некоторое распространенное заблуждение состоит в том, что получение значений небезопасно и их всегда следует избегать.

вы можете установить тип движка таблицы на «память» в mysql, если вы хотите добиться совершенства производительности.

person Uğur Gümüşhan    schedule 15.11.2011

Я бы порекомендовал, в дополнение к тому, что большинство заявило здесь о передаче зашифрованной информации, смотреть на это так же, как если бы вы передавали конфиденциальную информацию через сторонний API. Откуда вы знаете, что кто-то не подделывает запрос? Существует множество протоколов для действительного подтверждения подлинности запроса, в зависимости от того, насколько чувствительны ваши настройки. Вы подвергаете себя риску взлома учетных записей, если не будете осторожны.

Даже если он находится на том же сервере, учтите следующее:

Когда кто-то переходит по ссылке, формирует действие и т. д., которые передаются зашифрованному ключу, что может помешать кому-то перехватить его ДО того, как он попадет на защищенную версию вашего сайта? Если бы я был в общедоступной точке WIFI, это не было бы слишком надуманным. Я мог бы притвориться вашим сайтом, перенаправить запросы на свой ноутбук, получить токен и перенаправить посетителя туда, откуда он пришел. Они бы предположили, что это был сбой, и не имели бы ни малейшего представления. Теперь я могу войти в систему как они и, возможно, пойти купить вещи на 10 000 долларов с их кредитной картой и отправить их куда-нибудь еще. Степень осторожности, которую вы проявляете здесь, должна соответствовать степени чувствительности.

Кроме того, убедитесь, что срок действия ваших токенов истек (только одно использование, через X секунд и т. д.), но я бы также рассмотрел возможность использования шаблона Post-Redirect-Get на обоих концах, то есть:

Не показывайте прямую ссылку на странице или в форме незащищенного сайта, но покажите ссылку, которая затем будет перенаправлять на серверную часть (и обрабатывать все токены/шифрование). Когда вы доберетесь до защищенной версии, сделайте то же самое (не оставляйте параметр «?token=asdfjalksfjla» в URL-адресе; перенаправьте его).

Таким образом, формальные системы на основе токенов были разработаны для решения именно этой проблемы, но внедрение OAuth только для этого может быть излишним. Потратьте некоторое время на планирование потенциальных уязвимостей перед выполнением. Тот факт, что будет очень сложно угадать токен, не означает, что это невозможно (или не может быть коллизий и т. д.), так что планируйте соответствующим образом.

Вам также может понадобиться более сложная система управления сессиями, чем встроенные обработчики PHP. Я не знаю, можете ли вы заставить PHP продолжать сеанс при нескольких посещениях (переключение протоколов обрабатывается таким образом).

person landons    schedule 16.11.2011

Подумайте об использовании HTTPS для всех страниц, это самый простой способ избежать этой проблемы и повысить безопасность вашего сайта.

Если SSL для всех страниц вам не подходит, вы можете использовать этот подход: secure-session-cookie">Переключение между страницами HTTP и HTTPS с помощью файла cookie безопасного сеанса. Идея заключается в том, что вы оставляете файл cookie сеанса незащищенным (и, следовательно, доступным для страниц HTTP и HTTPS), но имеете второй безопасный файл cookie для обработки аутентификации. Это хороший способ разделить две задачи: "поддержание сеанса" и "аутентификация".

person martinstoeckli    schedule 16.11.2011

Вы можете управлять сеансом между HTTP-HTTPS или HTTPS-HTTP:

  1. Передать идентификатор сеанса между страницами с помощью GET

  2. Идентификатор сеанса POST по POST

  3. Используйте файлы для сохранения сессий

  4. Использовать файлы cookie для сеансов

  5. Использовать базу данных для сохранения сеанса

Пример ниже можно использовать для передачи с помощью GET….

Файл: http.php ……………

<?php

session_start();

$sessionID = session_id();

$_SESSION['demo'] = ‘Demo session between HTTP HTTPS’;

echo ‘<a href=”https://www.svnlabs.com/https.php?session=’.$sessionID.’”>Demo session from HTTP to HTTPS</a>’;

?>

Файл: https.php ……………

<?php

$sessionID = $_GET['session'];

session_id($sessionID);

session_start();

if (!empty($_SESSION['demo'])) {
echo $_SESSION['svnlabs'];
} else {
echo ‘Demo session failed’;
}

?>

IE7: эта страница содержит как безопасные, так и небезопасные элементы.

Вы должны использовать относительный путь для всех статических ресурсов на странице, таких как css, js, изображения, flash и т. д., чтобы избежать безопасных и небезопасных элементов сообщений IE…

Сообщение IEСообщение IE

person Rohan Patil    schedule 17.11.2011
comment
Передача идентификатора сеанса в URL сделает вас уязвимым для всех видов атак. Причина передачи идентификатора сеанса только с помощью файла cookie заключается в том, что вы можете принудительно зашифровать отправку файла cookie. - person martinstoeckli; 17.11.2011

Это может быть невозможно, так как файл cookie, похоже, теряется. Используемый вами браузер должен думать, что он для совершенно другого домена.

Какой браузер вы используете конкретно?

person Allain Lalonde    schedule 14.01.2009

По умолчанию я ожидаю, что браузер будет рассматривать подключения к http и https как совершенно разные сеансы. Хотя по соглашению http://someUrl/ и https://someUrl/ будет указывать на ту же страницу, что не гарантируется. У вас могут быть совершенно разные сайты, работающие на порту 80 (http) и порте 443 (https).

Я не знаю PHP, но обычно я не ожидаю, что переменные сеанса будут свободно доступны между безопасными и незащищенными сеансами, например. Я бы не ожидал, что номер кредитной карты из моей последней проверки будет доступен для всех последующих небезопасных страниц, которые я посещаю.

Простите за неавторитетный ответ, но я подумал, что забросил свой 2c, так как ответов не так много.

person codybartfast    schedule 14.01.2009
comment
Я бы этого вообще не ожидал. Проблема может быть связана с маскировкой проблем с путями / безопасными флагами. Хотя условность такова... - WTF? Нет, это действительно опасная практика. - person symcbean; 17.11.2011
comment
@symcbean То, что оба URL-адреса указывают на одну и ту же страницу, не означает, что они оба доступны. Конечно, «безопасная» страница доступна только через https. Чего вы не видите, так это http//someUrl и https//someUrl, указывающих на совершенно разный контент, но это вполне возможно. У банка не будет http на защищенном сервере, но многие сайты будут привязывать 80 и 443 к одному и тому же серверу, как и вопрошающий. - person codybartfast; 18.11.2011

У вас есть выделенный IP? в некоторых общих средах https и http маршрутизируются через разные серверы, поэтому при переключении фактически теряется доступ к файлам cookie, поскольку они находятся в разных доменах.

решения будут: выделенный ip

форсирование https на всех страницах в любое время

person Brian Barrett    schedule 13.07.2015

У меня была аналогичная проблема, однако это решение мне помогло, возможно, поможет другим в будущем.

добавьте это в свой php.ini

suhosin.session.cryptdocroot = Выкл.

suhosin.cookie.cryptdocroot = Выкл.

person Willian Santana    schedule 26.07.2016

У меня есть решение. Попробуйте.

$_SESSION['test'] = 'test';
session_regenerate_id(true);

header("Location: /");// the header must be sent before session close
session_write_close(); // here you could also use exit();
person UWU_SANDUN    schedule 18.09.2016

У меня была эта проблема при переходе с http на https, и я смог решить эту проблему, изменив URL-адрес веб-сайта с http://example.com на https://www.example.com

добавление www к URL-адресу решило эту проблему для меня.

Спасибо.

person Midz Elwekil    schedule 11.02.2020

Не волнуйтесь, это нормальное поведение, потому что HTTPS должен быть безопасным, и он выполняет свою часть работы.

Ниже приведены некоторые приемы, с помощью которых вы можете поддерживать сеанс при переключении с HTTP на HTTPS.

  1. Передать идентификатор сеанса между страницами с помощью GET

  2. Идентификатор сеанса POST по POST

  3. Используйте файлы для сохранения сессий

  4. Использовать файлы cookie для сеансов

  5. Использовать базу данных для сохранения сеанса

Надеюсь, вы получите что-то через мой ответ.

person Sumair Zafar    schedule 16.11.2011