【问题标题】:Restrict the user to make limited request per Second限制用户每秒发出有限的请求
【发布时间】:2012-02-02 08:29:39
【问题描述】:

环境:
基于 Java-EE 的 Web 应用程序


问题
需要限制用户在同一秒内发出超过 5 个(例如)请求(主要是 BOT)


解决方案
作为基本设计,我计划在应用程序范围内有 2 个同步 Map

Map<String, Map<Long, Integer>>

String 用于请求的 sessionId

Long 用于当前的第二个表示

Integer 是保持请求计数


流程:

第 0 步:

配置Filter 拦截每个请求

第 1 步:

确定地图 我会看看当前的minute 是否为奇数,然后我会在mapOne 上添加数据,然后我会清除mapTwo

第 2 步:

流程图

int requestNoForThisSecond = mapXX.get(request.getSession().getId()).get(currentSecondRepresantationInLong);
if(requestNoForThisSecond <= 5){
          requestNoForThisSecond++; 
          mapXX.get(request.getSession().getId()).put(currentSecondRepresantationInLong, requestNoForThisSecond);
}else{
         response.sendRedirect();// redirect to some captcha page
    } 

第 4 步:

如果会话过期/用户注销,也会删除会话条目


这是针对问题的非常基本的设计

你们中的任何人有更好的想法/建议吗?

【问题讨论】:

  • 我认为这个问题与 Java 或 Java-ee 没有任何关系。不?我的意思是,这是关于一种方法的讨论,并且与语言无关。如果您希望我们实际检查您的代码,那么合适的站点是 CodeReview.StackExchange.com
  • 对会话 ID 的每秒有限请求或对用户每秒的有限请求,他可以在不同的浏览器中打开许多会话。
  • @jigar ok,用geolite ip地址数据库和java api怎么样。blog.anthonychaves.net/2006/07/14/…
  • 如果只针对机器人,你考虑过robots.txt中的Crawl-delay指令吗?有了它,您可以指定机器人在连续请求之间必须等待的秒数。每分钟 5 次,即为Crawl-Delay: 12。诚然,并非所有机器人都遵守它(本土/水蛭等),但像 Googlebot 这样自尊的机器人却如此。

标签: java security web-applications jakarta-ee


【解决方案1】:

有一个Synchronizer Token Pattern。建议使用此模式以防止重复提交、跨站点请求伪造等。Struts 广泛使用此模式(JavaRanch 中提到的示例)。


对于那些不知道同步器令牌模式如何工作的人,这里是:

  1. 用户请求页面。在服务器上,负责页面请求的控制器从页面中检索令牌(不是JSESSIONID)。
  2. 如果请求返回的令牌与会话中找到的令牌匹配,则它是有效令牌,请继续。
  3. 重置令牌(生成新令牌)并将其保存在会话中。因此,您每次都可以使用新令牌进行验证并返回到同一页面。

在您的建议中,您必须确定提交时间,计算检索到的会话令牌(使用 HttpSessionListener)并限制您的请求调用。

我希望这会有所帮助。

【讨论】:

    【解决方案2】:

    可能是一个非常糟糕的 hack,但是......

    实现一个自定义Set&lt;Long&gt;,如果您尝试将相同的长值推入超过阈值并将其用作值,.add() 操作将返回 false?

    代码如下所示:

    if (!theMap.get(whatever()).add(secondInLong))
        // threshold reached
    

    一个优点是它会在您当前的代码中禁止竞争条件:如果仅同步您的地图,则对会话数的检查不受保护。有了这个解决方案,就可以了。

    或者用某种锁包围代码,并使用“普通”映射。

    进一步考虑这个想法,您甚至可以使用委托实现自定义Map。然后将在地图本身内计算“秒长”表示,您不需要关心它。

    【讨论】:

      【解决方案3】:

      首先,我认为您应该忘记会话 ID 的概念,而改用 IP 地址。您不希望机器人向您发送必要的 cookie,以便您可以跟踪其会话,是吗?

      其次,我认为您的方法过于复杂。您所需要的只是 IP 地址到时间数组 [N] 的映射,其中 N 是一个固定数字,即您计划每秒允许的请求数。 (我假设它会相对较低。)因此,每次您有来自给定 IP 的请求时,您将数组的内容向下移动 1,并将新请求的时间添加到数组的末尾.然后,从最后一个索引处的时间减去数组索引 0 处的时间,这为您提供了该 IP 向您发送 N 个请求所花费的时间,您可以轻松地将其转换为每秒的请求数。

      另外,你可能会觉得这个讨论很有趣:https://softwareengineering.stackexchange.com/questions/126700/development-of-a-bot-web-crawler-detection-system

      【讨论】:

      • IP 地址可能不起作用,他将如何捕获隐藏在防火墙后面或 VPN 中的呼叫?
      • s,might,will, -- 会话ID这里必须使用的
      • 只有当我们谈论的是防火墙或 VPN 后面的 巨大 网络时,这才会造成问题,在这种情况下,从它连接的人只需要活着有一些节流。我认为这没有问题。
      • @fge 所以,你相信机器人会好心地发送会话 cookie?
      【解决方案4】:

      每秒 5 个请求相当于每 0.2 秒 1 个请求。那么为什么不简单地拥有一个存储用户的 sessionID 和最后一个 System.nanoTime() 的 Map,然后您的过滤器只需进行快速评估以检查自用户上次请求以来至少已经过去了 200 毫秒。

      【讨论】:

      • 可能是这样的情况,第一个请求在 1000 毫秒,第二个在 1001 毫秒,然后用户行为正常。您的想法很好,但这并不能完全满足规定的要求。谢谢!
      【解决方案5】:

      听起来很合理,类似于 this article 中针对 Spring验证码集成所建议的内容。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-18
        • 1970-01-01
        • 2018-03-23
        • 1970-01-01
        相关资源
        最近更新 更多