奇怪、烦人且非常随机的会话超时问题

3
我有一个相当大的PHP应用程序(数千个唯一的URL,带有各种角色的用户登录等)。在php.ini中,PHP的会话超时设置为1小时(3600秒)。登录的工作方式是这样的:当用户成功登录应用程序时,一些关于用户的信息将存储在$_SESSION中,包括用户名、真实姓名、角色ID等。在每个页面访问(常见代码)时,都会检查$_SESSION中是否存在这些变量,如果存在,用户将进入他们所请求的位置。如果变量不存在,则用户将被重定向到“未登录”页面。
这已经运行良好了几年,仍然运行良好 - 大多数情况下。非常随机地,会话似乎在没有任何警告或其他任何东西的情况下超时。对于已登录的用户,这看起来像这样:登录,做一些事情,导航到下一页 - 而不是被注销并返回“未登录”页面。自然地,这非常令人恼火。然而,这种行为的随机性使得调查极其困难。
我从未在我的机器上在任何浏览器中遇到过这个问题。办公室里有另一台机器,在所有浏览器中都会出现这个问题(至少我可以复制这个问题)。在另一台机器上,它在一个浏览器中发生,在另一个浏览器中不会发生。而在另一台机器上,有时会发生,有时不会发生。今天,我们接到了一位客户的电话,他们遇到了这个问题 - 但是当要求在不同的浏览器中尝试时,它正常工作。
这不是由于浏览器的版本,因为它在某些机器上可以工作,在其他机器上则不能工作。此外,即使有两台完全相同的设置的机器,它有时会在其中一个上发生,但永远不会在另一个上发生。因此,总体而言,会话似乎发生了非常奇怪的事情,但我完全不知道该去哪里寻找。我已经试图调查这个问题几个月了,但没有任何进展。还有哪些地方需要查看?
此时,任何帮助都比非常感激。
补充:这是我的php.ini文件中的“session”部分:
[Session]
session.save_handler = files
session.use_cookies = 1
session.name = PHPSESSID
session.auto_start = 0
session.cookie_lifetime = 0
session.cookie_path = /
session.cookie_domain =
session.cookie_httponly = 
session.serialize_handler = php
session.gc_divisor     = 100
session.gc_maxlifetime = 3600 
session.bug_compat_42 = 1
session.bug_compat_warn = 1
session.referer_check =
session.entropy_length = 0
session.entropy_file =
session.cache_limiter = nocache
session.cache_expire = 180
session.use_trans_sid = 0
session.hash_function = 0
session.hash_bits_per_character = 4

1
假设会话使用cookies,请转到重现问题的框,连接好像Fiddler这样的良好HTTP代理,并查看出现问题的请求是否有任何异常。这将告诉您问题是在客户端还是服务器端(或者可能是因素的组合),并可能为您提供大量跟进的线索。 - Jon
顺便说一下,这通常发生在旧机器上。办公室里出现问题的两台机器几乎总是超过3年以上。请不要建议升级硬件,因为我们的大多数客户都是政府机构,他们使用的硬件/软件比我们落后许多年。几个月前我们停止支持IE6时,我们遭受了巨大的反弹(并失去了一个重要客户)。 - Aleks G
你使用的是哪种会话处理程序? - WayneC
@wgcrouch 我的代码中有 session.save_handler = filessession.serialize_handler = php - Aleks G
1
我猜测你的cookie在这些浏览器中由于一些奇怪的行为而超时了。当会话丢失时,你应该检查一下cookie是否还存在... - bardiir
1
为什么不编写一个脚本,在用户每次访问新页面时重新保存会话,并且每隔15分钟保存一次呢? - nathan hayfield
1个回答

0

我曾经遇到过同样的问题:在一些机器上会随意超时,而在其他机器上则一直如此,并且在大多数机器上根本不会出现这种情况。经过许多试错之后,我发现我的问题是由于某些使用IE的机器存在紧凑的隐私政策问题。我们只需添加一个类似于这样的标头 header('P3P: CP=Visit www.oururl.tld for our Privacy Policy.'),就可以解决旧版IE的很多问题。这只应该适用于第三方cookie,但谁知道IE会怎么做。

其次,我发现当设置session cookie为.domain.tld然后从domain.tld访问它而不是www.domain.tld时,一些机器会出现问题。确保所有请求都被定向到www子域名解决了大部分其他浏览器的问题。

最后,由于我们服务器的时区导致自动设置会出现问题,我必须接管php设置会话超时。我只需将过期时间设置为0,这样直到用户关闭浏览器或类似操作,“会话”结束前,它就永远不会超时,直到浏览器使用cookie。然后我向会话中添加一个简单的expires变量,并手动检查它,以便在我们服务器的时区而不是客户机的时区中做出所有关于过期的检查和决策。

这三件事情解决了除了那些最难以重现的情况之外的所有问题,我强烈怀疑这些问题是由Google和Yahoo工具栏对浏览器缓存或浏览器临时互联网文件本身做出奇怪的操作引起的。

如果您使用它们,您还可能想检查并确保您没有遇到会话ID重新生成和AJAX/其他异步调用的竞态条件。在旧版浏览器中,当您重新生成ID时,cookie通常不会更新得足够快,甚至在较新的浏览器中,时间也可能稍微有所偏差,从而提交旧的ID与新请求一起导致会话断开。我最好的解决方案是不要在AJAX上重新生成会话ID,而只在实际页面加载时进行,以保持同步。还有几种其他方法,例如保留旧的会话数据而不是自动删除它(仅应用程序的需求可以确定安全性程度)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接