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

时间:2009-01-14 00:47:07

标签: php session ssl https

将用户发送到结帐页面时,会将其从http://sitename.com切换为https://sitename.com

因此,$_SESSION变量将丢失。

该网站拥有有效的SSL证书,可能会或可能没有用。

16 个答案:

答案 0 :(得分:69)

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

来自PHP: session_start

  

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

使用会话时,通常会使用session_start()启动脚本。如果浏览器设置了会话ID cookie,session_start()将使用该会话ID。如果浏览器没有设置会话ID cookie,session_start()将创建一个新的。

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

...

$currentSessionID = session_id();

...

$currentSessionID变量设置为等于当前会话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的同一物理机器上运行)。这里存在一些安全漏洞,因此我不会使用此代码来传输敏感信息。它只是一个可行的例子。

当我遇到这个问题之前,我想出了上面的快速修复,但我只记得问题的原因。我是从http://www.example.com/page.phphttps://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,我实际上并没有运行这些脚本,因此可能会出现一两个错误,导致它们无法正常运行。

答案 1 :(得分:16)

听起来会话cookie设置为安全。 Cookie具有"secure"标志,如果设置为true,则表示该Cookie不会发送到非https网站。 PHP可能正在使用它的会话cookie。您可以使用session_set_cookie_params函数或php.ini中的session.cookie_secure设置更改此设置。

答案 2 :(得分:12)

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

关于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

答案 3 :(得分:6)

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

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

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

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

答案 4 :(得分:1)

看起来您的会话cookie是使用安全标志创建的,但是您的结帐页面的网址会有一些内容,因为会话cookie不会被传递。

或者,您的会话Cookie可能不安全 - 只是结帐页面的网址与浏览器不发送Cookie的距离不同(http://mysite.com vs http://www.mysite.com)。

如果您想阅读更多关于从http翻到https的信息,反之亦然 - 请查看at my writeup on selective ssl: - )

答案 5 :(得分:1)

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

sha1($string)

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

不同域上的发布方法会导致浏览器显示安全消息,因此请勿使用该方法。

使用url for get方法并不安全,您需要在重定向页面上要求输入密码以允许系统中的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

这非常安全。

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

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

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

答案 6 :(得分:1)

除了大多数人在此处所说的关于传输加密信息的内容之外,我建议您查看它,就像通过第三方API传输敏感信息一样。你怎么知道有人不是在欺骗这个请求?有许多协议可以真实地确认请求的真实性,具体取决于您的设置的敏感程度。如果你不小心的话,你会打开自己的帐户。

即使它位于同一台服务器上,请考虑以下事项:

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

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

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

因此,正式的基于令牌的系统被设计用于解决这个问题,但是为此实现OAuth可能是过度的。花一些时间在执行之前规划潜在的漏洞。仅仅因为猜测令牌非常强烈 并不意味着它是不可能的(或者不会发生碰撞等),所以要做出相应的计划。

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

答案 7 :(得分:1)

考虑在所有网页上使用HTTPS,这是避免此问题的最简单方法,它可以提高网站的安全性。

如果所有页面的SSL都不是您的选项,那么您可以使用以下方法: Switching between HTTP and HTTPS pages with secure session-cookie。背后的想法是,您使会话cookie不安全(因此可用于HTTP和HTTPS页面),但有第二个安全cookie来处理身份验证。这是将“维持会话”和“身份验证”这两个问题分开的好方法。

答案 8 :(得分:1)

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

  1. 使用GET

  2. 在页面之间传输会话ID
  3. POST POST会话ID

  4. 使用文件保存会话

  5. 使用Cookie进行会话

  6. 使用数据库保存会话

  7. 以下示例可用于使用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,images,flash等,以避免IE消息安全和不安全的项目......

    IE Message IE消息

答案 9 :(得分:0)

这可能是不可能的,因为cookie似乎迷失了。您正在使用的浏览器必须认为它适用于完全不同的域。

您具体使用哪种浏览器?

答案 10 :(得分:0)

默认情况下,我希望浏览器将与http和https的连接视为完全不同的会话。虽然惯例是http://someUrl/https://someUrl/将指向同一页面,但不能保证。您可以在端口80(http)和端口443(https)上运行完全不同的站点。

我不知道PHP,但通常我不希望会话变量在安全和非安全会话之间免费提供,例如我不希望我上次结账时的信用卡号可用于我访问的所有后续不安全页面。

原谅非权威性答案,但我认为自己已经知道我的2c,因为答案不多。

答案 11 :(得分:0)

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

解决方案是: 专用的IP

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

答案 12 :(得分:0)

我有类似的问题,但是,这个解决方案对我有好处,也许将来会帮助别人

在你的php.ini

中添加它

suhosin.session.cryptdocroot = Off

suhosin.cookie.cryptdocroot = Off

答案 13 :(得分:0)

我有一个解决方案。试试吧。

$_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();

答案 14 :(得分:0)

我遇到了从http到https的问题,并且能够解决将网站URL从http://example.com更改为https://www.example.com的问题

将www添加到URL中为我解决了这个问题。

谢谢。

答案 15 :(得分:-1)

不要担心这是一种正常行为,因为HTTPS本身就是安全的,而且它正在尽自己的一份力量。

以下是一些技巧,您可以在从HTTP切换到HTTPS时维护会话。

  1. 使用GET

  2. 在页面之间传输会话ID
  3. POST POST会话ID

  4. 使用文件保存会话

  5. 使用Cookie进行会话

  6. 使用数据库保存会话

  7. 希望你能通过我的回复得到一些答案。