环境:
基于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步:
如果会话过期/用户注销
,也会删除会话条目这是问题的基本设计
你们中的任何一个人有更好的想法/建议吗?
答案 0 :(得分:3)
首先,我认为您应该忘记会话ID的想法,而是使用IP地址。您不希望机器人向您发送必要的cookie,以便您可以跟踪其会话,对吗?
其次,我认为你的方法不必要地复杂化。您只需要一个IP地址到时间数组[N]的映射,其中N是固定数字,即您计划每秒允许的请求数。 (我假设它会相对较低。)因此,每当您收到来自给定IP的请求时,您将数组内容向下移动一步,并将新请求的时间添加到数组末尾。然后,从最后一个索引的时间中减去数组索引0处的时间,这将为您提供IP向您发送N个请求所花费的时间,您可以将其转换为每秒请求数。
此外,您可能会发现此讨论很有趣:https://softwareengineering.stackexchange.com/questions/126700/development-of-a-bot-web-crawler-detection-system
答案 1 :(得分:1)
可能是一个非常糟糕的黑客但是......
如果您尝试将相同的长值推送到超过阈值并将其用作值,那么实现Set<Long>
操作返回false的自定义.add()
?
然后代码如下:
if (!theMap.get(whatever()).add(secondInLong))
// threshold reached
一个优点是它会禁止您当前代码中的竞争条件:如果仅同步您的地图,则不会保护对会话数的检查。有了这个解决方案,它就是。
或者使用某种锁定环绕代码,并使用“普通”地图。
进一步考虑这个想法,你甚至可以实现一个带委派的自定义Map
。然后,在地图本身内计算“长秒”表示,您不需要处理它。
答案 2 :(得分:1)
5秒请求每0.2秒相当于1个请求。那么为什么不简单地使用一个Map存储sessionID和用户的最后一个System.nanoTime(),然后你的过滤器只需要进行快速评估,以检查自用户上次请求以来至少已经过了200ms。
答案 3 :(得分:1)
有一个Synchronizer Token Pattern。建议使用此模式以防止双重提交,跨站请求伪造等.Struts广泛使用此模式(示例在JavaRanch上提及)。
对于那些不知道Synchronizer Token Pattern如何工作的人,请点击这里:
JSESSIONID
)。 在您的建议中,您必须对提交时间进行计时,检索会话令牌(使用HttpSessionListener
)并限制您的请求呼叫。
我希望这会有所帮助。
答案 4 :(得分:0)
听起来很合理,类似于this article中针对Spring&lt; - &gt; captcha集成的建议。