【问题标题】:PHP session HTTP to HTTPS problemPHP会话HTTP到HTTPS问题
【发布时间】:2011-08-20 18:18:07
【问题描述】:

我有一个 (HTTPS) login.php 页面,它仍然是 HTTPS(即一旦用户登录到帐户仪表板)。现在的问题是说用户在登录到安全仪表板时点击了一个非敏感页面,如(HTTP)about-us.php 页面,会话不是通过 HTTP 传输的,因为我有 session.cookie_secure=1,这意味着用户在 HTTP 页面上显示为已注销。

但是,当用户返回仪表板页面或任何敏感帐户页面时,我被告知他仍应登录(即从 HTTP 返回到 HTTPS)?然而事实并非如此,他似乎也退出了 HTTPS 连接?

我相信我遗漏了导致此问题的某些内容。这是我的代码:

这是在 login.php 页面上调用以启动会话的 PHP 头文件:

session_start();
session_regenerate_id(true); /*avoid session fixation attempt*/

/*Create and check how long session has been started (over 5 mins) regenerate id - avoid session hijack*/
if(!isset($_SESSION['CREATED'])) 
{
    $_SESSION['CREATED'] = time();/*time created session, ie from login/contact advertiser/email_confirm only ways for new session to start*/
} 
elseif(time() - $_SESSION['CREATED'] > 300) 
{
    /*session started more than 5 mins(300 secs) ago*/
    session_regenerate_id(true); /*change session ID for the current session and invalidate old session ID*/
    $_SESSION['CREATED'] = time(); /*update creation time*/
}

/*Check if user is logged in*/
if(!isset($_SESSION['loggedin']))
{
    $_SESSION['loggedin']=1;/*used to track if user is logged in on pages*/
}

/*if return false browser supports standard ob_start();*/
if(ob_start("ob_gzhandler")){ob_start();}

这是每个页面都需要的 PHP 头文件,用于检查会话是否已经启动:

session_start(); 

$session_errors=0;/* if>0 user not logged in*/

/*check if session is already initiated*/
if(isset($_SESSION['CREATED'])) 
{
    if(time() - $_SESSION['CREATED'] > 300) 
    {
        /*session started more than 5 mins(300 secs) ago*/
        session_regenerate_id(true); /*change session ID for the current session and invalidate old session ID*/
        $_SESSION['CREATED'] = time(); /*update creation time*/
    }
}
elseif(!isset($_SESSION['CREATED'])){$session_errors++;}/*user not logged in*/

/*Check if user is logged in*/
if(!isset($_SESSION['loggedin'])){$session_errors++;}/*user not logged in*/

if(ob_start("ob_gzhandler")){ob_start();}

如果有任何用途,这是在非敏感页面(例如 about-us.php)上打开 HTTPS 的代码

if ($_SERVER['SERVER_PORT']!=80)
{
$url = "http://". $_SERVER['SERVER_NAME'] . ":80".$_SERVER['REQUEST_URI'];
header("Location: $url");
}

我的 php.ini 文件 cookie 设置

session.cookie_secure=1
session.cookie_httponly=1
session.use_only_cookies=1
session.cookie_lifetime = 0
session.save_path = /tmp
session.save_handler = files

【问题讨论】:

  • 看上面的问题(虽然不要听从它的建议),当用户移动到http连接时,cookie没有被传输,所以当session_start()被调用时,它会生成一个新的会话ID ,因此之前的会话 id 会丢失。
  • @rickchristie,我已阅读该主题,唯一的方法似乎是将安全 cookie 标志设置为“关闭”。但这肯定是不安全的,因为我的 session_id 不能在 HTTP 页面上被嗅探吗?我不想通过 URL 大量安全漏洞发送 session_id。
  • 是的,这是一个巨大的安全漏洞,这就是为什么我告诉你不要听从它的建议:) - 我有一个解决方案,作为答案发布在下面,尽管它可能不是你想要的解决方案。

标签: php http https session-state


【解决方案1】:

回答以帮助可能偶然发现此问题的人

正如Session lost when switching from HTTP to HTTPS in PHP 的答案已经得出结论,由于您使用的是session.cookie_secure = 1,因此当连接从HTTPS 切换到HTTP 时,不会传输包含会话ID 的cookie。在 HTTP 连接中,当你 session_start() 时,PHP 会创建一个新的会话 id,它会替换之前的会话 id。

答案还提出了一个解决方案,使用查询字符串传递会话 ID,然后由页面获取。这闻起来很糟糕的安全漏洞。不要忘记我们最初使用 HTTPS 的原因!

所以我向您建议的解决方案是您将所有 http 请求重定向到 https 对应对象。对站点中的所有内容使用 HTTPS,从 CSS、图像到普通的静态 html 页面。这实际上是每个认真对待安全性的应用程序都会做的事情。例如,使用 HTTP 访问 github 页面会返回:

HTTP/1.1 301 Moved Permanently
Server: nginx/0.7.67
Date: Sun, 08 May 2011 15:43:01 GMT
Content-Type: text/html
Content-Length: 185
Connection: close
Location: https://github.com/

<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/0.7.67</center>
</body>
</html>

请记住您最初使用 HTTPS 的原因,如果您想完全安全,请使用 HTTPS。

在引导时检测请求是否为 HTTPS (See this question)

如果请求是 HTTP,请将所有请求重定向到 HTTPS 主页,或者您可以尝试解析 $_SERVER['REQUEST_URI'] 并使用 parse_urlhttp_build_url 将 HTTP 请求重定向到对应的 HTTPS。


第二种替代解决方案

如果您真的不想对所有内容都使用 HTTPS,那么请不要在使用 HTTP 访问的页面上session_start()。执行此操作时将保留安全 cookie。


第三种替代解决方案

另一种解决方案是尝试通过 IP 地址和用户代理检测用户。这不能保证准确,所以我建议对所有内容都使用 HTTPS。例如,即使是普通的静态页面,Paypal 也始终使用 HTTPS。

【讨论】:

  • 你的意思是“如果你真的不想对所有事情都使用 HTTPS,那么不要在使用 HTTP 访问的页面上使用 session_start()。当你这样做时,将保留安全 cookie这。”您的意思是在非敏感页面上保留 HTTPS,但不使用 session_start()?那么只有在用户登录时,我才应该对所有内容使用 HTTPS 吗?
  • @daza - 该声明是另一个解决方案的一部分,已更新以使其更清晰
  • @daza - 只需对所有内容使用 HTTPS,即使是未登录的用户。
  • 感谢您的信息,我已决定在所有页面上使用 HTTPS,这似乎是最简单的方法,而不必过于复杂。
【解决方案2】:

@rickchristie 的描述很好,但我认为他没有建议更好的解决方案。如果您不总是想使用 HTTPS(有时确实有意义;about_us 页面不需要安全),您可以按照session_start 页面上的建议并使用named sessions 继续上一个会话.这很容易使用;只需将session_start 调用包含在

session_name("MySession"); // replace with whatever makes sense
session_start();

在所有安全页面上。

【讨论】:

    猜你喜欢
    • 2011-06-26
    • 1970-01-01
    • 1970-01-01
    • 2011-07-06
    • 2011-03-13
    • 2010-10-01
    • 2011-08-02
    • 2010-12-25
    相关资源
    最近更新 更多