您如何防止用户通过按住刷新键来关闭您的应用程序?

Posted

技术标签:

【中文标题】您如何防止用户通过按住刷新键来关闭您的应用程序?【英文标题】:How do you prevent a user from taking down your application by holding down the refresh key? 【发布时间】:2022-01-17 17:57:17 【问题描述】:

我最近在 nginx/Rails 应用服务器上发生了中断。事实证明,我们正受到对特定 URL 的请求的轰炸,这些请求需要几秒钟才能加载。似乎用户在几分钟内不断刷新该页面 - 我猜他们不小心在键盘上放置了一些对象,从而触发了持续的浏览器刷新流。

无论是什么原因,我都需要针对此类问题采取保护措施,并注意这不是静态内容 - 它是身份验证之后的动态、特定于用户的内容。

我已经研究过使用 Cache-Control 但这似乎是一个非首发 - 至少在 Chrome 上,无论 Cache-Control 标头如何,刷新同一选项卡中的页面都会触发请求(参见 iis - Is Chrome ignoring Cache-Control: max-age? - Stack Overflow )

我相信答案可能是速率限制。如果是这样,我将无法基于 IP 来做,因为我们的许多客户共享同一个。但是我可以添加一个新标头来识别用户,然后基于此在 Nginx 中应用速率限制。

这听起来像是前进的方向吗?这感觉应该是一个相当普遍的问题!

【问题讨论】:

缓存在导轨一侧。您没有理由不能根据页面参数在设定的时间间隔内缓存响应或基础数据,因此无论刷新多少次,您都可以跳过昂贵的处理。 这是一种非常常见的场景,被称为专用 Dential of Service 攻击。 Rack 应用程序(如 Rails)中的速率限制可以使用 Rack::Attack gem 来完成。但是如果可能的话,在它上面的层(例如NGinX)上做它是非常有利的。如果您在 Rack 层执行此操作,则每个请求仍会访问您的 Rails 服务器。 缓存在这里不太奏效——它真的取决于客户端来“尊重”缓存控制标头,因此它不能提供针对恶意攻击者的 DDOS 攻击的保护。一个例外是反向缓存,它在一定程度上减轻了影响,因为请求只会访问您的缓存而不是您的应用程序,但它仅适用于内容可缓存的情况。 考虑到它是一个经过身份验证的用户导致了这个问题,在这种情况下限制速率似乎有点过分了。而且您不必缓存整个内容 - 只需缓存底层数据表示通常就足够了。 【参考方案1】:

Nginx rate limiting 是一个快速配置更新,如果需要立即缓解。正如其他人所提到的,与此结合使用缓存也是理想的选择。

server 
  # DoS Mitigation - Use IP and User Agent to prevent against NAT funnels from different computers
  limit_req_zone $host$binary_remote_addr$http_user_agent zone=rails_per_sec:10m rate=2r/s;

  upstream rails ...

  try_files $uri $uri/ @rails;

  location @rails 
    limit_req zone=rails_per_sec burst=10 nodelay;
    ...
  

$http_authorization 标头或唯一 cookie(例如 $cookie_foo)也可用于唯一标识与相同 IP/用户代理值冲突的请求。

limit_req_zone $host$binary_remote_addr$http_authorization  ...;
limit_req_zone $host$binary_remote_addr$cookie_foo          ...;

【讨论】:

以上是关于您如何防止用户通过按住刷新键来关闭您的应用程序?的主要内容,如果未能解决你的问题,请参考以下文章

防止用户关闭通知

如何防止导航器推送刷新屏幕

在手机上按住按钮时如何防止附近的文本选择?

在ASP中如何防止用户频繁刷新网页

如何通过按键盘上的一个键来防止调用多个 KeyDown 事件?

防止SQLite Magellan破坏您的应用程序