【问题标题】:How to get around server flooding by users opening countless tabs?如何通过用户打开无数标签来避免服务器泛滥?
【发布时间】:2012-07-11 18:12:06
【问题描述】:

我有某种聊天/论坛应用程序,它使用 jquery ajax 定期轮询(每 15 秒)检查新消息。我想知道我是否可以通过加载几个相同的浏览器实例来解决用户试图变得“有趣”的问题,这些浏览器实例有很多选项卡,都指向同一个应用程序。每个选项卡都在发送一个 ajax 请求,如果多个用户开始做同样的事情,这可能会导致服务器溢出。

我确实将会话以及上次访问时间和 IP 地址存储在一个表中,只要用户不使用相同的浏览器,它就可以正常工作。我可以存储一个使用 ajax POST 或 GET 请求发送的唯一标识符,但是如果常规(非滥用)用户刷新他的页面,这会产生问题,然后会创建一个新的标识符。

这还不是一个真正的问题,但最好在有人想到像这样滥用系统之前抓住它:) 知道如何做到这一点吗?

【问题讨论】:

  • 我能想到的唯一可能做的事情是某种速率限制(即:限制每个会话/时间段的轮询请求数)。
  • 嗯,这是我还没有想到的。我确实有某种限制,它会在 5 分钟不活动后停止 ajax 轮询,但我可以扩展一点。
  • 实际上,使用 PHP 并不能真正做到这一点,因为这仍然需要一个 ajax 请求。是否可以使用javascript对其进行限制?换句话说,同一浏览器中的所有选项卡是否都知道彼此和彼此的请求,并通过使用 javacsript 来限制它?基本上,是否有一个内部浏览器计数器可以看到刚刚在选项卡 X 中完成了一个请求,并且在其中有代码以便选项卡 Y 不会再发送 ajax 请求?
  • JS 变量会在每次页面加载时重新实例化,因此变量不能跨选项卡共享。但是,您可以在页面加载时向服务器端脚本发送请求,该脚本会跟踪请求的数量,并在执行其他任何操作之前将其发送回客户端。
  • 您能否在该用户的会话中存储上次检索消息时的时间戳?然后无论他们使用什么浏览器/选项卡,PHP 都可以检查并确保分配的时间已经过去。

标签: php ajax


【解决方案1】:

一种选择可能是这样获取数据:

  • 您的脚本正在准备轮询数据。在执行请求之前,写入(使用LocalStorage),一个表示您将要获取数据的值。 localStorage.setItem("last-request-timestamp", new Date().getTime());
  • 轮询数据。你得到一个结果。将该结果写入本地存储:localStorage.setItem("latest-messages", ajax_result);
  • 通过检查 localStorage.getItem("last-request-timestamp") 是否超过 15 秒来检查页面是否准备轮询数据。如果是,请转到步骤 1。如果不是,请等待 15 秒并再次检查。
  • 无论当前页面是否轮询数据,检查latest-messages 变量并更新页面。

其他页面当然会共享 localStorage 数据。如果此时正在获取另一个页面,他们将不会获取数据。如果页面 #1 关闭,其他页面之一将继续获取数据。

我以前没有使用过 LocalStorage,但浏览器支持似乎还不错。您还应该能够将其用作键值数组:localStorage["last-request-timestamp"]

localStorage 中只能存储字符串,当然也可以序列化成 JSON。

【讨论】:

  • 有趣,我以前没有听说过这个。我假设这可以在 jquery 代码块中设置和使用,因此这仅适用于某些请求。我会调查一下,谢谢:)
【解决方案2】:

不确定它是否可以在 javascript 中使用。您可以检查选项卡是否处于活动状态。并且只在活动选项卡上做 ajax?

【讨论】:

  • 这可能是一个使用 onfocus/onblur 或其他东西的想法。不确定这是否适用于所有浏览器和移动设备,但值得一试。
【解决方案3】:

我也有类似的问题。现在我强制所有用户登录(这意味着我有他们的电子邮件)。我还设置了每个帐户的连接限制和每个连接的请求限制,在 5 次溢出后我要求用户输入验证码,然后我阻止帐户 30 分钟并发送带有密码恢复链接的电子邮件。这不是一个明确的解决方案,但现在它对我有用。

UPD:

最简单的方法是使用 cookie 或会话存储。我使用饼干。算法很简单:

  1. 用户在网络上登录。
  2. 检查该用户是否有任何打开的会话, 被打开,然后删除其他会话或触发异常或 切换到那个会话,你已经决定了你自己想要的 行为。
  3. 为用户创建会话 ID 并将其存储在数据库中。
  4. 增加特定用户的会话计数器字段以检测打开 会话,所以现在是否有一个浏览器正在使用并不重要 或许多。
  5. 更新最后一个访问标记(我使用microtime(true) + $delay和mysql decimal(14,4))。发送给用户
  6. 发送 id 给客户

对每个请求:

  1. 通过 $_COOKIE 中传递的 id 搜索会话。
  2. 检查最后一个访问标记。如果小于microtime(true),则表示客户端发送请求频繁,所以自己决定要做什么,增加标记,例如microtime(true) + $delay + $penalty或丢弃整个会话或触发错误。行为取决于您的应用程序。

【讨论】:

  • 如果该用户从同一个浏览器多次连接,如何获取该用户的连接数?随每个 POST 或 GET 发送的唯一标识符?请求限制是没有用的,因为这仍然需要将 ajax 请求发送到服务器,如果达到限制,服务器会检查它。
  • @RikkusRukkus 依赖 localStorage 是不安全的,因为它的数据可以被用户修改
  • 会话和 cookie 都用于同一个会话/域,所以我不确定这是否适用于我的情况。我会看看我是否可以测试这个。关于本地存储。我认为只有一小部分普通用户会知道如何操作 LocalStorage 数据,因此这可能会排除大多数“恶作剧者”。我可能只会将“最后执行时间”存储在此类 LocalStorage 变量中。
【解决方案4】:

为什么不在问题上抛出 Memcached/Redis 之类的东西呢?以 10-15 秒的生命周期缓存响应,并尽可能避免处理。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-17
    • 2021-03-02
    • 1970-01-01
    • 2016-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多