【问题标题】:Race Condition for Persistent "Remember Me" Cookies持久“记住我”Cookie 的竞争条件
【发布时间】:2011-08-22 09:04:50
【问题描述】:

根据Persistent Login Cookie Best Practice,您绝不应允许多次使用“记住我”令牌:

持久性 cookie 适合单次登录。确认身份验证后,用于登录的随机数无效,并分配一个全新的 cookie。标准会话管理在会话的生命周期内处理凭据,因此新分配的 cookie 将在下一个会话之前检查(此时它也将在使用后失效)。

那么,您如何处理用户同时访问您网站上的多个 URL 的竞争条件?我现在确实遇到了这个问题。

假设两个请求同时从浏览器发送到服务器。请求不包含会话 cookie,但包含相同的“记住我”cookie。其中一个请求将在另一个请求之前得到处理,并将获得一个带有经过身份验证的会话 cookie 和重新生成的“记住我”cookie 的响应。

第二个请求中的“记住我”令牌现已失效,并在服务器上生成另一个会话 ID。此请求失败,因为无法对用户进行身份验证。

我想出了一些可能的解决方案,但似乎都不是很好。我错过了什么吗?

【问题讨论】:

  • 我开始意识到问题是由于 http 是无状态的。如果“记住我”令牌没有立即失效,响应仍然会返回不同的会话(并且浏览器会用最后一个会话覆盖旧会话)。

标签: authentication cookies login race-condition


【解决方案1】:

老问题,但我在任何地方都找不到答案。 我有同样的问题。我的解决方案是将旧令牌存储在数据库中,并在找不到主令牌时将其用作后备。但我确保旧令牌仅在短时间内有效,例如令牌更改后的几秒钟。然后我只在上次更新后经过一段时间才更改令牌,否则会出现令牌连续更改多次的情况。

【讨论】:

    【解决方案2】:

    为了详细说明 vangoz 的答案,我要补充一点,也必须采用某种锁定机制。在这里考虑一下这个 PHP-ish 伪代码:

    if (isFallback($token)) {
      // Log the user in
    } else {
      // Usual processing
      // If token has to be updated, save old token as fallback for a few seconds
    }
    

    当有并发请求时,它们可能都在 else 分支中结束,一个请求将导致更新,另一个将导致令牌无效。我解决这个问题的方法是使用以$token 命名的命名锁来包装 else 分支。此外,除了一个请求之外的所有并发请求都将无法获取锁,在这种情况下,我们会稍作睡眠并重试(重试后,我们会发现令牌已成为备用令牌)。

    if (isFallback($token)) {
      // Log the user in
    } else {
      $couldLock = lock($token);
      if (!$couldLock) {
        usleep(10000);
        // Retry, possibly a recursive call
      } else {
        // Usual processing
        // If token has to be updated, save old token as fallback for a few seconds
        unlock($token);
      }
    }
    

    我希望这些注意事项有用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-08
      • 1970-01-01
      • 1970-01-01
      • 2022-01-23
      • 2018-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多