【问题标题】:Yii 1.1: Race Condition when reading $_COOKIE used to identify userYii 1.1:读取用于识别用户的 $_COOKIE 时的竞争条件
【发布时间】:2026-01-13 23:45:01
【问题描述】:

当 2 个用户(几乎)同时访问同一页面时,我遇到了争用情况。这会导致用户获得对其他用户数据的访问权限。

几个月来,我一直在努力解决这个问题,终于成功了。 我使用的是Yii Framework 1.1,用户登录流程如下:

  • 会话存储在数据库中,我实际上并没有使用 $_SESSION 来存储任何东西。
  • 生成的会话 ID 存储在 cookie 中并填充 $_COOKIE,PHP 使用该 ID 将用户连接到他们的数据。
  • 在登录页面中,我将 cookie 中的会话 ID 存储在表单的一个字段中。
  • 用户登录,输入被验证,会话数据被创建并与用户记录一起存储,包括来自表单的会话ID(真实的会话ID)。然后,用户将通过另外 2 个控制器(LoginCheck、Dashboard)进入 Dashboard。
  • 在会话期间,用户会频繁返回仪表板。
  • 当 2 个或更多用户(几乎)同时访问仪表板页面(通过登录或从站点内的页面返回)时,两个用户最终将获得相同的 cookie id 和会话数据。我可以通过使用存储在 $_COOKIE 变量中的 cookie 值检查基于浏览器的 cookie 来确认这一点。使用不正确的数据在页面上简单刷新仪表板会导致加载正确的数据。

我研究了 PHP 会话的竞争条件,其中一些提供使用 $_COOKIE 来解决会话的竞争条件,因此并没有真正为我的问题提供任何解决方案。

由于我能够捕获问题,我可以通过刷新轻松解决它,但如果有更稳定的解决方案可用,我更愿意走这条路。

任何建议将不胜感激。

干杯

【问题讨论】:

  • 听起来您的会话 ID 生成是基于时间戳的。例如,如果您使用的是uniqid,那么这很容易导致您的问题。您应该研究使用加密安全值生成 ID 的替代方法,例如通过random_intrandom_bytes
  • 除此之外,如果不查看任何实际代码,我们将无法真正为您提供帮助。这个问题可能是由许多事情引起的。我们需要查看代码才能缩小范围。
  • 您的会话管理确实有问题。 session_id() php.net/manual/en/function.session-id.php 在每个会话中始终是唯一的。来自不同浏览器的用户无法获得相同的会话 ID。直到您人为地将其替换为损坏的实现。它与竞态条件无关
  • 提供代码的问题大部分来自 Yii 框架,所以我一直假设/相信它会按预期工作。很难追踪这种情况发生的方式和时间,但我现在已经做到了。
  • @GregJ 我们不一定需要您的框架样板代码,但知道您使用哪个类来存储会话数据和/或生成会话 ID 和任何特定于应用程序的会话-相关的代码可以看看。

标签: php yii session-cookies yii1.x


【解决方案1】:

您可以使用带有 x 或 x+ 标志的 fopen 来共享文件。只有其中一个实例可以同时打开文件。

但是您所描述的内容不一致且奇怪:在使用您所描述的会话时,您不应该需要处理竞争条件。我想问题在于您在每次页面加载时重新生成会话 ID,因此您可能正在做一些您不应该做的事情。

在会话中,每个用户代理必须只生成一次会话 ID,但正如您所描述的,该 ID 在每次页面更改时都会重新生成,并且作为次要问题,它是以低熵生成的。

如果你解决了第一个问题,那么低熵问题将得到缓解,但并未解决。

【讨论】:

  • 对任何混淆表示歉意,但会话 ID 不会在每次页面加载时重新生成。创建会话时,SessionID 会存储在 cookie 中,并且该 cookie 会一直保留到会话到期或用户注销为止。我正在使用 Yii 框架提供的核心功能,但我还没有完全理解它实际上是如何工作的。