Limit the user to make a limited request per second

Environment:
Java-EE Based Web Application


Problem :
It is necessary to limit the user to receiving more than 5 (for example) requests within the same second (BOTs mainly)


Solution :
As a base project, I plan to have 2 synchronized Map in the application area

 Map<String, Map<Long, Integer>> 

String is for sessionId request

Long for the current second view

Integer - hold the number of requests


Process:

Step 0:

Configure Filter to intercept each request

Step 1:

determine the map I will see if the current minute odd, then I will add data to mapOne and I will clear mapTwo

Step 2:

process map

 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 } 

Step 4:

also delete the session record if the session ends / the user logs out


This is a very simple design for the problem.

Do any of you have a better idea / suggestion?

+4
source share
5 answers

First of all, I think you should forget the idea of ​​a session identifier and use IP addresses instead. You do not expect the bot to send you the necessary cookies so you can track its session, right?

Secondly, I think your approach is unnecessarily complicated. All you need is an IP address map with an array of time [N], where N is a fixed number, the number of requests you plan to allow per second. (I assume that it will be relatively low.) Thus, every time you have a request from a given IP address, you shift the contents of the array by one and add the time of the new request to the end of the array. Then you subtract the time with index 0 of your array since the last index, and this gives you the time it takes for the IP address to send you N requests, which you can trivially convert to the number of requests per second.

Also, this discussion may seem interesting: https://softwareengineering.stackexchange.com/questions/126700/development-of-a-bot-web-crawler-detection-system

+3
source

Probably a very bad hack, but ...

Implement custom Set<Long> for which the .add() operation returns false if you are trying to push the same long value more than the threshold and use it as values?

Then the code will look like this:

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

One of the advantages is that the race condition would be forbidden in your current code: if only your card is synchronized, checking the number of sessions is not protected. With this solution, this.

Or surround the code with some kind of lock and use a β€œnormal” card.

Taking this idea further, you can even implement custom Map with delegation. Then the "long in second" view will be counted in the map itself, and you will not need to worry about that.

+1
source

5 queries the second equivalent of 1 query every 0.2 seconds. So, why not just have a card that stores the sessionID and the last System.nanoTime () of the user, and your filter then only needs to perform a quick assessment to check what has passed since the last user request for at least 200 ms.

+1
source

Here's the sync marker pattern . This model was proposed to prevent double submission, cross-site Forgery query, etc. Struts makes extensive use of this pattern (an example is given in JavaRanch ).


For those who don’t know how the Token Pattern works, it says:

  • The user requests a page. On the server, the controller responsible for requesting the page retrieves a token (not JSESSIONID ) from the page.
  • If the token returned from the request matches the token found in the session, this is a valid token, continue.
  • Reset token (generate a new token) and save it in the session. Thus, you can validate and return to the same page with a new token every time.

In your proposal, you will need the time of your submission, count the session token retrieved (using the HttpSessionListener ), and limit your request.

Hope this helps.

+1
source

It sounds reasonable and looks like what was suggested in this article for Spring ↔ captcha integration.

0
source

Source: https://habr.com/ru/post/1389264/


All Articles