PHP 会话 HTTP 到 HTTPS 问题
我有一个(HTTPS)login.php 页面,该页面仍然是HTTPS(即用户登录后进入帐户仪表板)。现在的问题是,用户在登录到安全仪表板时单击了非敏感页面,例如(HTTP)about-us.php 页面,会话不会通过 HTTP 传输,因为我有 session.cookie_secure=1,这意味着用户在 HTTP 页面上显示为已注销。
但是,当用户返回仪表板页面或任何敏感帐户页面时,我被告知他仍然应该登录(即从 HTTP 回到 HTTPS)?但事实并非如此,他似乎也已在 HTTPS 连接上注销?
我相信我错过了导致此问题的某些东西。这是我的代码:
这是 PHP 头文件,被调用以在 login.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();}
此外,如果有任何使用,这是将 HTTPS 转换为 HTTPS 的代码在非敏感页面,例如 about-us.php
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
I have a (HTTPS) login.php page which remains HTTPS (ie once user logged in goes to account dashboard). Now the problem is say the user whilst logged on to the secure dashboard clicks onto a non-sensitive page like (HTTP) about-us.php page, the session is not transmitted over HTTP as I have session.cookie_secure=1, meaning the user appears logged out on HTTP pages.
However when the user goes back to dashboard page or any sensitive account page I have been told he should still be logged in (ie from HTTP back to HTTPS)? However this is not the case and he appears logged out on the HTTPS connection too?
I believe I am missing something which is causing this problem. Here is my code:
This is PHP header file which is called to start session on login.php page:
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();}
This is PHP header file required on every page to check if session initiated already:
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();}
Also if any use this is the code to turn HTTPS of on non-sensitive pages such as about-us.php
if ($_SERVER['SERVER_PORT']!=80)
{
$url = "http://". $_SERVER['SERVER_NAME'] . ":80".$_SERVER['REQUEST_URI'];
header("Location: $url");
}
My php.ini file cookie settings
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
@rickchristie 的描述很好,但我认为他没有建议更好的解决方案。如果您并不总是想使用 HTTPS(有时确实有意义;about_us 页面不需要安全),您可以遵循
session_start
页面并使用 命名会话 继续上一个会话。这个使用起来很简单;只需在所有安全页面上包含session_start
调用即可。
The description by @rickchristie is good, but I think there's a better solution that he doesn't suggest. If you don't always want to use HTTPS (which does make sense sometimes; the about_us page doesn't need to be secure), you can follow the advice on the
session_start
page and use named sessions to continue a previous session. This is simple to use; just include thesession_start
calls withon all secure pages.
回答是为了帮助可能偶然发现此问题的人
作为 在 PHP 中从 HTTP 切换到 HTTPS 时会话丢失 已结束,因为您使用的是
session.cookie_secure = 1
包含会话 ID 的 cookie 是未转移时连接从 HTTPS 切换到 HTTP。在 HTTP 连接中,当您使用session_start()
时,PHP 会创建一个新的会话 id,它会替换之前的会话 id。答案还提出了一个解决方案,使用查询字符串传递会话 ID,然后由页面获取。这闻起来有点糟糕的安全缺陷。不要忘记我们最初使用 HTTPS 的原因!
因此,我向您建议的解决方案是将所有 http 请求重定向到 https 对应项。对站点中的所有内容使用 HTTPS,从 CSS、图像到普通的静态 html 页面。这实际上是每个重视安全性的应用程序都会做的事情。例如,使用 HTTP 访问 github 页面将返回:
记住为什么你首先使用 HTTPS,如果你想完全安全,就使用 HTTPS。
检测请求是否为 HTTPS (请参阅这个问题) 在引导程序中。
如果请求是 HTTP,则将所有请求重定向到 HTTPS 主页,或者您可以尝试解析
$_SERVER['REQUEST_URI']
并使用parse_url
和http_build_url
。第二种替代解决方案
如果您真的不想在所有事情上都使用 HTTPS,那么就不要在通过 HTTP 访问的页面上使用
session_start()
。当您执行此操作时,将保留安全 cookie。第三种替代解决方案
另一种解决方案是尝试通过 IP 地址和用户代理检测用户。这不能保证准确,所以我建议一切都使用 HTTPS。例如,Paypal 始终使用 HTTPS,即使对于普通的静态页面也是如此。
Answered to help people who might stumble across this
As the the answer at Session lost when switching from HTTP to HTTPS in PHP has concluded, since you are using
session.cookie_secure = 1
the cookie that contains the session ID is not transferred when the connection switches from HTTPS to HTTP. At HTTP connection, when yousession_start()
, PHP creates a new session id, which replaces the previous session id.The answer also suggests a solution, pass the session id using query string, which is then picked up by the page. This smells of bad of security flaw. Don't forget the reason why we used HTTPS in the first place!
So the solution I suggest to you is that you redirect all http request to https counterparts. Use HTTPS for everything in your site, from css, images, to mundane static html pages. This is actually something that every application that is serious about security does. For example, visiting github page using HTTP will return:
Remember why you used HTTPS in the first place, if you want to be totally secure, use HTTPS for everything.
Detect if the request is HTTPS or not (See this question) at bootstrap.
If the request is HTTP, either redirect all requests to HTTPS home page, or you can try parsing
$_SERVER['REQUEST_URI']
and redirecting HTTP request to their HTTPS counterpart usingparse_url
andhttp_build_url
.Second Alternative Solution
If you really really don't want to use HTTPS for everything, then don't
session_start()
on pages that are accessed with HTTP. Secure cookies will be retained when you do this.Third Alternative Solution
The other solution is to try and detect the user by IP addresses and user agent. This is not guaranteed to be accurate, so what I suggest is just use HTTPS for everything. Paypal, for example, always use HTTPS even for mundane static pages.