在PHP中从HTTP切换到HTTPS时会话丢失
将用户发送到结帐页面时,他们从http://sitename.com
切换到https://sitename.com
。
因此, $_SESSION
variables会丢失。
该网站有一个有效的SSL证书,可能会或可能不会有一些使用。
当您在同一台服务器上的HTTP和HTTPS服务之间切换时,您的HTTP会话标识未被传递给HTTPS会话。 您可以通过以下三种方式之一将会话ID从HTTP页面传递到HTTPS页面来进行设置:
来自PHP:session_start :
session_start()
创build一个会话,或者根据通过请求传递的当前会话ID来恢复当前会话,例如GET,POST或者cookie
在使用会话时,通常会使用session_start()
启动脚本。 如果浏览器设置了会话ID cookie, session_start()
将使用该会话ID。 如果浏览器没有设置会话ID cookie, session_start()
将创build一个新的会话ID。
如果未设置会话ID(在您的示例中,浏览器正在为HTTPS会话创build新的会话ID cookie),则可以使用session_id()
函数进行设置。 session_id()
也方便地以stringforms返回会话ID。 所以
... $currentSessionID = session_id(); ...
设置$currentSessionID
variables等于当前会话ID,
... session_id($aSessionID); ...
将浏览器中的sessionID cookie设置为$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在同一台物理机上运行)。 这里有一些安全漏洞,所以我不会使用这个代码来传输敏感信息。 这只是一个可行的例子。
当我遇到这个问题之前,我想出了上述的一个快速解决scheme,但我只记得这个问题的原因。 我从http://www.example.com/page.php去https://example.com/page.php (注意缺less“www”)。 确保http://www.example.com/page.php链接到https://www.example.com/page.php,并且http://example.com将链接到https://example.com /page.php 。
PS,我没有真正运行这些脚本,所以可能有一个错字或两个,以防止他们正常运行。
听起来像会话cookie被设置为安全的。 Cookie有一个“安全”标志,如果设置为true,则意味着cookie不会被发送到非https站点。 PHP可能使用它的会话cookie。 您可以使用session_set_cookie_params函数或php.ini中的session.cookie_secure设置进行更改。
我们也有这个问题。 原来是因为我们在我们的PHP安装中使用了suhosin补丁。 我们通过在/etc/php.d/suhosin.ini
设置suhosin.session.cryptdocroot = Off
来解决这个问题。
有关suhosin.session.cryptdocroot的suhosin手册,请参阅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 。
以下解决scheme假定安全服务器和非安全服务器可以访问相同的后端服务(caching,数据库存储等)。
当用户完成购物时,我们必须处理同样的问题。 为了解决这个问题,我们放置了一个caching层并caching了所有相关的数据。 例如,我们会从会话值中收集产品ID和用户ID,序列化它们,创build一个散列,最后使用散列作为关键字将会话数据存储在caching中。 然后,我们会将用户redirect到安全网站的url中的散列。
当用户在安全站点上结束时,我们将尝试从基于散列的caching中提取数据。 然后使用用户标识和产品ID,我们可以将所有定价和描述数据从数据库中加载出来,并提交给用户进行最终结账审查。
caching数据是不稳定的,但是我们从来没有遇到任何问题,因为redirect很快就会发生。
看起来你的会话cookie是用安全标志创build的,但是你的结账页面的url有一些东西,因为会话cookie没有被传递过来。
或者,您的会话cookie不是安全的 – 只是结账页面的url与浏览器不发送cookie的url不同( http://mysite.com vs http://www.mysite.com )。
如果你想阅读更多关于从http到https翻转,反之亦然 – 请看看我在selectssl :-)的写作
您不能在不同的域之间传递会话值。 您必须使用http post-get或数据库来传递您的值。 为了安全起见,您可以将所有的值串联起来并使用
sha1($string)
并将其与您的值一起发布,然后计算其他页面获取的值的sha1,然后比较哈希值。
不同域的Post方法会导致浏览器显示安全信息,所以不要使用它。
使用get方法的url是不安全的,您需要在redirect的页面上要求input密码,以允许系统中的get参数。
如果您需要安全,请不要使用cookies。
我build议的方式是,将值保存在数据库中并生成一个密钥,然后使用您的密钥创buildredirect链接,使用带有密钥的get参数转发用户页面,然后redirect页面用户以获取该密钥,提取数据并删除密钥。 你可以用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
这是相当安全的。
可能发生的事情:为参数“key”input随机值的脚本,使您的网站将数据加载到内存中?
这不会发生,因为您在使用后删除条目。 一些常见的误解是,获取值是不安全的,应该始终避免。
你可以将表引擎types设置为mysql中的“内存”,如果你想要完美的performance。
除了这里提到的大部分关于传输encryption信息的内容之外,我还build议您将其视为与通过第三方API传输敏感信息一样。 你怎么知道有人不欺骗请求? 有很多协议可以真正确认请求的真实性,具体取决于您的设置有多敏感。 如果你不小心,你会打开自己的帐户被入侵。
即使它在同一台服务器上,请考虑这一点:
当有人正在关注通过encryption密钥的链接,表单操作等时,有什么方法可以防止某人在获取到网站的安全版本之前嗅探它? 如果我在公共WIFI点,那不会太牵强。 我可以假装成你的网站,将请求重新路由到我自己的笔记本电脑,获取令牌,并将访问者redirect到他们来的地方。 他们会认为这是一个小故障,并不知道。 现在我可以login他们,并可能去购买价值10,000美元的东西与他们的信用卡存档,并将其运往其他地方。 您在这里采取的谨慎程度应该与敏感程度相匹配。
此外,请确保您的令牌过期(仅在X秒后使用一次,等等),但我也会考虑在两端使用Post-Redirect-Get模式,即:
不要在页面上或以不安全的站点的forms显示直接链接,而是显示一个链接,然后在后端redirect(并处理所有的令牌/encryption的东西)。 当你到达受保护的版本,做同样的事情(不要留下一个“?token = asdfjalksfjla”参数只是坐在那里的URL;redirect它)。
所以,正式的基于令牌的系统就是为了解决这个问题而devise的,但是仅仅为此而实现OAuth可能是过度的。 花一些时间在执行之前计划潜在的漏洞。 只是因为猜测这个令牌真的很难 ,并不意味着这是不可能的(或者不可能有碰撞等等),所以要相应地进行规划。
您也可能需要比PHP内置的处理程序更复杂的会话pipe理系统。 我不知道是否可以强制PHP跨多次访问继续会话(切换协议是这样处理的)。
考虑在所有页面上使用HTTPS,这是避免这个问题的最简单的方法,它会提高网站的安全性。
如果所有页面的SSL都不是您的select,那么您可以使用这种方法: 使用安全的会话cookie在HTTP和HTTPS页面之间切换 。 背后的想法是,您将会话Cookie保持不安全状态(因此可用于HTTP和HTTPS页面),但有第二个安全Cookie来处理身份validation。 这是将“维护会话”和“身份validation”这两个问题分开的好方法。
您可以pipe理HTTP到HTTPS或HTTPS到HTTP之间的会话:
-
使用GET传输页面之间的会话ID
-
通过POST POST会话ID
-
使用文件保存会话
-
使用Cookies进行会话
-
使用数据库来保存会话
下面的例子可以用来传输使用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:此页面包含安全和非安全项目
你必须使用相对path的所有静态资源的页面,如CSS,JS,图像,闪存等,以避免IE消息安全和不安全的项目…
IE消息
这可能是不可能的,因为cookie似乎正在迷失。 您使用的浏览器必须认为它是一个完全不同的域。
你使用什么浏览器?
默认情况下,我希望浏览器将http和https的连接视为完全不同的会话。 虽然约定是http:// someUrl /和https:// someUrl /将指向相同的页面,但不能保证。 您可以在端口80(http)和端口443(https)上运行完全不同的站点。
我不知道PHP,但通常我不希望会话variables在安全和非安全会话之间自由可用,例如,我不希望从最后一次签出的信用卡号码可用于所有随后的不安全页面I访问。
原谅非权威的答案,但我想我会在我的2c查找,因为没有太多的答案。
你有专门的IP吗? 在一些共享的环境中,https和http是通过不同的服务器路由的,所以实际上切换失去了对cookie的访问,因为它们在不同的域上。
解决scheme将是:专用IP
强制在所有页面上的https
我也有类似的问题,但是这个解决scheme对我有好处,也许会在未来帮助别人
添加这个在你的php.ini
suhosin.session.cryptdocroot =关
suhosin.cookie.cryptdocroot =关
我已经得到了一个解决scheme..试试吧。
$_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();
不要担心,这是一个正常的行为,因为HTTPS是为了安全起见,它正在尽自己的一份力量。
以下是一些技巧,通过它们可以在从HTTP切换到HTTPS的同时维护会话。
-
使用GET传输页面之间的会话ID
-
通过POST POST会话ID
-
使用文件保存会话
-
使用Cookies进行会话
-
使用数据库来保存会话
希望你能通过我的回复得到一些东西。