13

假设有一个登录会员区的站点/系统,用户很少,但在使用该站点/系统时注销非常不方便。

这可能是会话即将到期,因为用户没有闲置很长时间。即使它们空闲,我也添加了一个周期性的 AJAX 请求,即所谓的心跳,它会更新会话的访问时间和修改时间。我什至在每次用户单击某些东西或调用心跳时添加一个 touch($session_file) 。我也尝试重新生成会话 ID。没有任何帮助。

不幸的是,到目前为止,我无法在本地重现该问题,因为它经常发生,当有更多请求时。一些 php.ini 参数:

session.use_cookies = 1
session.use_only_cookies = 1
session.cookie_lifetime = 0
session.gc_probability = 1
session.gc_divisor = 1500
session.gc_maxlifetime = 10800
4

5 回答 5

6

由于会话和身份验证已经通过代码中的一个超级控制器处理,因此至少排除会话破坏应该很容易。

通常只有登录页面会创建会话,因此此时您可以(并且应该)在其中添加一个已知值,例如会话 ID。

其他页面(包括您的心跳)恢复现有会话,因此此时您查找上述值;如果它丢失了,你可以做更多的检查:

  • 会话 cookie 是否通过?如果没有,浏览器/cookie 问题。
  • 会话 cookie 是否对应session_id()?如果没有,会话文件由于垃圾收集而丢失。
  • 会话中是否存在已知值?如果没有,会话被截断或有人试图进行会话采用攻击。
  • 已知值是否与会话 cookie 对应?如果不是,则会话是通过与 cookie 不同的方式建立的;你可以检查session.use_only_cookies设置。

上面的一组检查应该为您指明正确的方向。

于 2012-08-13T09:04:42.277 回答
3

我想您正在使用内置的 PHP 文件会话存储?它存在已知的竞争条件问题。

当有来自同一会话 ID 的并发请求时,我遇到了丢失会话 ID 的类似问题。由于文件被第一次请求锁定,所有其他并发连接都无法访问文件,并且其中一些生成了新的会话 ID。这些情况也非常罕见,我花了一些时间来定位问题。从那以后,我使用 memcached 进行会话存储,这些问题就消失了。

于 2012-08-14T18:46:48.667 回答
2

如果没有进一步的信息,我很难回答这个问题,但是你确定只有当你有更多的流量时才会发生这种情况。可以做什么:

  • 添加代码
  • 操作系统发行版和版本
  • PHP版本

您是否有任何依赖 IP 的会话检查。如果是这样,可能是您实际上使用了一个代理,该代理每隔一段时间就会提供一次不同的 IP(如 Cloudflare),在这种情况下,您可以使用HTTP_CF_CONNECTING_IP来获取实际不变的 IP。

我还注意到一件事:

session.use_only_cookies = 1
session.cookie_lifetime = 0

所以cookie实际上会在浏览器关闭时被销毁。是否有可能因为用户关闭选项卡(在某些浏览器中确实清除了 cookie)而导致连接丢失?

正如其他人所建议的那样,我强烈建议您转到数据库会话。使用中央会话存储可以帮助停止竞争条件,它不会完全停止它们,但它确实使它更难。此外,如果你真的得到那么多会话 id,你可能想考虑使用内置 PHP 会话 id 以外的东西,但是内置哈希非常独特,重复的可能性非常低,所以我不认为那是你的问题。

澄清编辑:

如果您使用与 Cloudflare 不同的代理,那么您当然需要获取代理集的 HTTP 标头,使用 Cloudflare 就是一个示例。

于 2012-08-21T20:42:56.943 回答
0

这是我用过的东西。它使用 javascript 以 10 分钟的间隔“ping”服务器。

<form method="POST" target="keepalive-target" id="keepalive-form">
    <input type="hidden" name="keepalive-count" id="keepalive-count">
</form>
<iframe style="display:none; width:0px; height:0px;" name="keepalive-target"></iframe>
<script>
    var kaCount=0;
    setInterval(function()
    {
        document.getElementById("keepalive-count").value=kaCount++
        document.getElementById("keepalive-form").submit();
    },600000);
</script>
于 2012-08-22T07:35:40.843 回答
0

所有提供的答案都显示了对该问题的良好洞察力,但我只需要分享我的确切问题的解决方案。我终于能够重现问题并修复它。

所以系统包含两个子系统,比如说管理和客户端界面。管理员在另一个选项卡中以客户端身份登录并在以管理员身份登录时注销客户端界面时意外注销。这样做是因为所有内容都写入一个带有命名空间的会话。我所做的是删除在注销操作时不断破坏会话的代码,并将其替换为会话命名空间取消设置并替换为仅有权访问登录页面的命名空间的访客会话。

于 2012-11-24T13:09:16.063 回答