在 PHP 中从 HTTP 切换到 HTTPS 时会话丢失

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/441496/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 22:45:33  来源:igfitidea点击:

Session lost when switching from HTTP to HTTPS in PHP

phpsessionsslhttps

提问by Allan

When sending the user to a checkout page, they are switched from http://sitename.comto https://sitename.com.

将用户发送到结帐页面时,他们将从 切换http://sitename.comhttps://sitename.com

As a result, $_SESSIONvariables are lost.

结果,$_SESSION变量丢失。

The site has a valid SSL certificate which may or may not be of some use.

该站点具有有效的 SSL 证书,该证书可能有用也可能没有用。

回答by Jacob

When you switch between the HTTP and HTTPS services on the same server, your HTTP session ID is not being passed to the HTTPS session. You can set it by passing the session ID from the HTTP page to the HTTPS page in one of three possible ways:

当您在同一服务器上的 HTTP 和 HTTPS 服务之间切换时,您的 HTTP 会话 ID 不会传递到 HTTPS 会话。您可以通过以下三种可能的方式之一将会话 ID 从 HTTP 页面传递到 HTTPS 页面来设置它:

From PHP: session_start:

来自PHP: session_start

session_start()creates a session or resumes the current one based on the current session id that's being passed via a request, such as GET, POST, or a cookie

session_start()根据通过请求(例如 GET、POST 或 cookie)传递的当前会话 ID 创建会话或恢复当前会话

When you are using sessions, you will normally start your script with session_start(). If the browser has a session ID cookie set, session_start()will use that session ID. If the browser does not have a session ID cookie set, session_start()will create a new one.

当您使用会话时,您通常会以session_start(). 如果浏览器设置了会话 ID cookie,session_start()将使用该会话 ID。如果浏览器没有设置会话 ID cookie,session_start()则会创建一个新的。

If the session ID is not set(in your example, the browser is creating a new session ID cookie for the HTTPS session), you can set it using the session_id()function. session_id()also conveniently returns the session ID as a string. So

如果未设置会话 ID(在您的示例中,浏览器正在为 HTTPS 会话创建新的会话 ID cookie),您可以使用该session_id()函数进行设置。session_id()还可以方便地将会话 ID 作为字符串返回。所以

...

$currentSessionID = session_id();

...

sets the $currentSessionIDvariable equal to the current session ID, and

$currentSessionID变量设置为等于当前会话 ID,并且

...

session_id($aSessionID);

...

sets the sessionID cookie in the browser to $aSessionID. from PHP: session_id

将浏览器中的 sessionID cookie 设置为$aSessionID. 来自PHP:session_id

Here's an example with two scripts. One is accessed via HTTP and the other is accessed via HTTPS. They must be on the same server to maintain session data.

这是一个包含两个脚本的示例。一个通过 HTTP 访问,另一个通过 HTTPS 访问。它们必须在同一台服务器上才能维护会话数据。

Script 1(HTTP):

脚本 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>';

?>

Script 2(HTTPS):

脚本 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.';
}

?>

For this to work the HTTP and HTTPS servers must use the same session data storage substrate (i.e. for the default files handler, run on the same physical machine with the same php.ini). There are some security flaws here, so I would not use this code to transfer sensitive information. It is just meant as a workable example.

为此,HTTP 和 HTTPS 服务器必须使用相同的会话数据存储基板(即对于默认文件处理程序,运行在具有相同 php.ini 的同一台物理机器上)。这里有一些安全漏洞,所以我不会使用这个代码来传输敏感信息。它只是作为一个可行的例子。

When I ran into this problem before, I came up with the above as a quick fix, but I just remembered the original cause of the problem. I was going from http://www.example.com/page.phpto https://example.com/page.php(notice the lack of "www"). Make sure that http://www.example.com/page.phpwill link to https://www.example.com/page.phpand http://example.comwill link to https://example.com/page.php.

之前遇到这个问题的时候,我想出了上面的快速解决方法,但我只是记住了问题的最初原因。我从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, I didn't actually run these scripts so there may be a typo or two that prevents them from running properly as is.

PS,我实际上并没有运行这些脚本,所以可能有一两个错字阻止它们按原样正常运行。

回答by JW.

Sounds like the session cookie is set to be secure. Cookies have a "secure"flag which, if set to true, means that the cookie won't be sent to non-https sites. PHP is probably using that for its session cookies. You can change this with the session_set_cookie_paramsfunction, or with the session.cookie_securesetting in php.ini.

听起来像会话 cookie 被设置为安全。Cookie 有一个“安全”标志,如果设置为 true,则意味着 cookie 不会发送到非 https 站点。PHP 可能将其用于其会话 cookie。您可以使用session_set_cookie_params函数或php.ini 中的session.cookie_secure设置更改此设置。

回答by Tom

We had this issue as well. It turned out to be because we were using the suhosinpatch on our PHP installation. We fix it by setting suhosin.session.cryptdocroot = Offin /etc/php.d/suhosin.ini.

我们也有这个问题。原来是因为我们在 PHP 安装中使用了suhosin补丁。我们通过设置suhosin.session.cryptdocroot = Off来修复它/etc/php.d/suhosin.ini

For the suhosin manual about suhosin.session.cryptdocrootsee http://www.hardened-php.net/suhosin/configuration.html#suhosin.session.cryptdocroot.

有关 suhosin 手册,suhosin.session.cryptdocroot请参阅http://www.hardened-php.net/suhosin/configuration.html#suhosin.session.cryptdocroot

We originally found the fix from this blog post: http://www.yireo.com/blog/general-news/315-switch-between-http-and-https-looses-php-session.

我们最初从这篇博文中找到了修复:http: //www.yireo.com/blog/general-news/315-switch-between-http-and-https-looses-php-session

回答by Mike Purcell

The following solution assumes the secure and non-secure servers have access to the same backend services (cache, database store, etc).

以下解决方案假设安全和非安全服务器可以访问相同的后端服务(缓存、数据库存储等)。

We had to deal with this same issue when sending a user to our checkout flow when they were done shopping. To solve this, we put in place a caching layer and cached all the pertinent data. For example, we would glean the product ids and user id from the session values, serialize them, create a hash, and finally store the session data within cache using the hash as the key. We would then redirect user to the secure site with the hash in the url.

在用户完成购物后将其发送到我们的结账流程时,我们不得不处理同样的问题。为了解决这个问题,我们放置了一个缓存层并缓存了所有相关数据。例如,我们将从会话值中收集产品 ID 和用户 ID,将它们序列化,创建一个哈希,最后使用哈希作为键将会话数据存储在缓存中。然后,我们会将用户重定向到带有 url 哈希值的安全站点。

When the user ended up on the secure site we would attempt to pull the data out of cache based on the hash. Then with the user id and product ids we could load all the pricing and description data out of the database and present to the user for final checkout review.

当用户最终访问安全站点时,我们将尝试根据哈希从缓存中提取数据。然后使用用户 ID 和产品 ID,我们可以从数据库中加载所有定价和描述数据,并将其呈现给用户以进行最终结账。

There is an inherit risk in that the cache data is volatile, but we have never had any issues with it as the redirect happens quickly.

存在缓存数据易变的继承风险,但我们从未遇到任何问题,因为重定向发生得很快。

回答by U?ur Gümü?han

You can't pass session values between different domains. You must use http post-get or a database to pass your values. For security, you can concat all your values in a string and use

您无法在不同域之间传递会话值。您必须使用 http post-get 或数据库来传递您的值。为了安全起见,您可以将所有值连接到一个字符串中并使用

sha1($string)

and post it alongside your values and calculate the sha1 for the values other page gets, then compare the hashes.

并将其与您的值一起发布并计算其他页面获取的值的 sha1,然后比较哈希值。

Post method on different domains cause browsers to show a security message, so don't use that.

不同域上的 Post 方法会导致浏览器显示安全消息,所以不要使用它。

Using url for get method is not safe, you would need to ask for a password on the redirected page for allowing the get parameters in your system.

使用 url for get 方法是不安全的,您需要在重定向页面上询问密码以允许系统中的 get 参数。

Do not use cookies if you need security.

如果您需要安全,请不要使用 cookie。

The way I am suggesting is, save the values in a database and generate a key, then make your redirection link using your key, forward the users page with a get parameter which has the key, then the page user is redirected to gets that key, fetches the data and removes the key. you can generate a key with sha1

我建议的方法是,将值保存在数据库中并生成一个密钥,然后使用您的密钥创建重定向链接,使用具有密钥的 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

this is pretty secure.

这是非常安全的。

the things that can happen: a script entering random values for the parameter "key" to make your website load the data into your memory?

可能发生的事情:脚本为参数“key”输入随机值以使您的网站将数据加载到您的内存中?

This is not going to happen because you delete the entry after using it. Some common misconception is that get values are unsafe and should always be avoided.

这不会发生,因为您在使用后删除了该条目。一些常见的误解是 get 值是不安全的,应该始终避免。

you can set the table engine type to "memory" in mysql if you want performance perfection.

如果您想要性能完美,您可以在 mysql 中将表引擎类型设置为“内存”。

回答by U?ur Gümü?han

Looks like your session cookie is created with the secure flag, but there's something with the url of your checkout page due to which the session cookie isnt being passed over.

看起来您的会话 cookie 是使用安全标志创建的,但是由于会话 cookie 没有被传递,结帐页面的 url 存在某些问题。

Or probably, your session cookie isnt secure - just that the url of the checkout page is different enough (http://mysite.comvs http://www.mysite.com) that the browser isnt sending the cookie.

或者可能,您的会话 cookie 不安全 - 只是结帐页面的 url 足够不同(http://mysite.comhttp://www.mysite.com),浏览器没有发送 cookie。

If you'd like to read more on flipping over from http to https and vice versa - do take a look at at my writeup on selective ssl:-)

如果您想阅读更多有关从 http 切换到 https 以及从 http 切换到 https 的内容,请查看我关于选择性 ssl 的文章:-)

回答by landons

I'd recommend, in addition to what most have stated here about transferring encrypted information, looking at it the same as if you were transferring sensitive information through a 3rd party API. How do you know someone isn't spoofing the request? There are many protocols for truly confirming the authenticity of the request, depending on how sensitive your setup is. You're opening yourself up to accounts being compromised if you're not careful.

除了此处大多数关于传输加密信息的说明之外,我还建议您将其视为通过 3rd 方 API 传输敏感信息。你怎么知道有人没有欺骗请求?有许多协议可以真正确认请求的真实性,具体取决于您的设置的敏感程度。如果您不小心,您就会让自己的帐户遭到入侵。

Even though it's on the same server, consider this:

即使它在同一台服务器上,请考虑:

When someone is following the link, form action, etc. that passes over the encrypted key, what would prevent someone from sniffing it BEFORE they get to the secured version of your site? If I were at a public WIFI spot, that wouldn't be too far-fetched. I could pretend to be your site, reroute requests to my own laptop, grab the token, and redirect the visitor back to where they came. They would assume it was a glitch, and would have no idea. Now I can login as them, and possibly go buy $10,000 worth of stuff with their credit card on file and ship it somewhere else. The degree of caution you take here should match the degree of sensitivity.

当有人关注传递加密密钥的链接、表单操作等时,什么会阻止他们在访问您网站的安全版本之前嗅探它?如果我在公共 WIFI 点,那不会太牵强。我可以假装是你的网站,将请求重新路由到我自己的笔记本电脑,获取令牌,并将访问者重定向回他们来的地方。他们会认为这是一个小故障,并且不知道。现在我可以以他们的身份登录,并且可能会使用他们的信用卡购买价值 10,000 美元的东西并将其运送到其他地方。您在此处采取的谨慎程度应与敏感程度相匹配。

Also, make sure you expire your tokens (one use only, after X number of seconds, etc), but I would also consider using the Post-Redirect-Get pattern on both ends, i.e.:

另外,请确保您的令牌过期(仅使用一次,在 X 秒后等),但我也会考虑在两端使用 Post-Redirect-Get 模式,即:

Don't show the direct link on a page or in the form of the unsecured site, but show a link that will then redirect on the backend (and handle all the token/encryption stuff). When you arrive at the secured version, do the same (don't leave a "?token=asdfjalksfjla" parameter just sitting there in the URL; redirect it).

不要在页面上或以不安全站点的形式显示直接链接,而是显示一个链接,然后在后端重定向(并处理所有令牌/加密内容)。当你到达安全版本时,做同样的事情(不要在 URL 中留下一个“?token=asdfjalksfjla”参数;重定向它)。

So, formal token-based systems were designed to solve this very problem, but implementing OAuth just for this might be overkill. Spend some time planning the potential vulnerabilities before executing. Just because it'd be really hardto guess the token doesn't mean it's impossible (or there couldn't be collisions, etc.), so plan accordingly.

因此,正式的基于令牌的系统旨在解决这个问题,但仅为此实施 OAuth 可能有点过头了。在执行之前花一些时间计划潜在的漏洞。仅仅因为很难猜测令牌并不意味着它不可能(或不可能发生冲突等),因此请相应地计划。

You also might need a more sophisticated session management system than PHP's built-in handlers. I don't know if you can force PHP to continue a session across multiple visits (switching protocols is treated that way).

您可能还需要一个比 PHP 的内置处理程序更复杂的会话管理系统。我不知道您是否可以强制 PHP 在多次访问中继续会话(切换协议就是这样处理的)。

回答by martinstoeckli

Think about using HTTPS for all pages, that's the easiest way to avoid this problem and it will improve the security of your site.

考虑对所有页面使用 HTTPS,这是避免此问题的最简单方法,它将提高您网站的安全性。

If SSL for all pages is not an option to you, then you could use this approach: Switching between HTTP and HTTPS pages with secure session-cookie. The idea behind is, that you leave the session cookie unsecure (and therefore available to HTTP and HTTPS pages), but have a second secure cookie to handle the authentication. It's a good way to separate the two concerns "maintaining the session" and "authentication".

如果所有页面的 SSL 不是您的选择,那么您可以使用这种方法: 使用安全会话 cookie 在 HTTP 和 HTTPS 页面之间切换。背后的想法是,让会话 cookie 不安全(因此可用于 HTTP 和 HTTPS 页面),但有第二个安全 cookie 来处理身份验证。这是将“维护会话”和“身份验证”这两个关注点分开的好方法。

回答by Rohan Patil

You can manage session between HTTP to HTTPS or HTTPS to HTTP:

您可以管理 HTTP 到 HTTPS 或 HTTPS 到 HTTP 之间的会话:

  1. Transmit session ID between page using GET

  2. POST session ID by POST

  3. Use files to save sessions

  4. Use Cookies for sessions

  5. Use database to save session

  1. 使用 GET 在页面之间传输会话 ID

  2. POST 会话 ID 通过 POST

  3. 使用文件保存会话

  4. 使用 Cookie 进行会话

  5. 使用数据库保存会话

Below example can be used to transmit using GET….

下面的示例可用于使用 GET... 进行传输。

File : http.php ……………

文件: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>';

?>

File: https.php ……………

文件:https.php ……………

<?php

$sessionID = $_GET['session'];

session_id($sessionID);

session_start();

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

?>

IE7 : This page contains both secure and nonsecure items

IE7:此页面包含安全和非安全项目

You have to use relative path for all static resource on page like css, js, images, flash etc. to avoid IE message secure and nonsecure items…

您必须对页面上的所有静态资源(如 css、js、图像、flash 等)使用相对路径,以避免 IE 消息安全和非安全项目……

IE MessageIE Message

浏览器消息浏览器消息

回答by Brian Barrett

Do you have a dedicated IP? on some shared environments the https and the http are routed through different servers, so switching actually loses access to the cookies since they're on different domains.

你有专用IP吗?在某些共享环境中,https 和 http 通过不同的服务器路由,因此切换实际上无法访问 cookie,因为它们位于不同的域中。

solutions would be: dedicated ip

解决方案是:专用IP

forcing https on all pages at all times

始终在所有页面上强制使用 https