dpanshu
dpanshu

Reputation: 463

Limit transactions per second (TPS) for every client in tomcat server without DOS vulnerability

I have a web service for which I need to limit the number of transactions a client can perform. A transaction is hitting the URL with correct parameters. Every client will have different number of transactions it can perform per second. Client will be identified based on the IP address or a parameter in the URL.

The maximum TPS a client can perform will be kept in database or any other configurable manner. I understand that it would be possible to write servlet filter to do this. The filter would calculate requests per second and make database connection to get maximum TPS of client and reject the request when TPS reached as it will further slow down the application response. But that will not be helpful during a DOS attack. Is there a better way?

Upvotes: 0

Views: 2770

Answers (1)

Jose Martinez
Jose Martinez

Reputation: 12022

I had to do the same thing. This is how I did it.

1) I had a data model for tracking an IP's requests. It mainly tracked the rate of requests by using some math that allowed me to add a new request and the new rate of requests for that IP would quickly be recalculated. Lets call this class IpRequestRate.

2) For each unique IP that made a request an instance of IpRequestRate was instantiated. Only one instance was required per IP. They were put into a HashMap for fast retrieval. If a new IP came in, then a new instance of IpRequestRate was created for it.

3) When a request came in, if there was already an instance of IpRequestRate in the HashMap, then I would add the new request to that instance and get the new rate. If the rate was above a certain threshold, then the request would not be processed.

4) If the requester accidentally went above that threshold, then the rate would quickly dip below the threshold. But if it was a real DOS, or in my case too many attempts to access an account (due to hackers), then it would take much longer for their rate to dip below the threshold; which is what I wanted.

5) I do not recall if I had a cleanup thread to remove old IP's but that's something that would be needed at some point. You can use EhCache as your HashMap so it could do this for you automatically.

6) It worked really well and I thought about open sourcing it. But it was really simple and easily reproducible. You just have to get that math down right. The math for getting the rate is easy to get it accurate, but a little tricky if you want it to be fast, so that not a lot fo CPU's are spent calculating the new rate when a new request is added to the IpRequestRate.

Does that answer your question or would you need more info on how to setup the Filter in your server?

Edit: WRT DOS, during a DOS attack we want to waste as little resources as possible. If it all possible DOS detection should be done in a load balancer or reverse proxy or gateway or firewall.

If we want to do per IP max transmission rate, which is stored in a database then I would just cache the max transmission rates. This can be done without doing DB lookup for a request. I would instead load the table into a HashMap.

1) At start of application, say in the init() method, I would load the table into a HashMap that maps IP to maxTransmissionRate.

2) When request comes in, try to get the maxTransmissionRate from the HashMap. If its not there then use a default maxTransmissionRate.

3) During the init(), kickoff a ScheduleExecutorService to update the HashMap at some desired interval, to keep the HashMap fresh. Here is the link to ScheduleExecutorService, its not that hard. http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledExecutorService.html

4) Which HashMap implementation should we use? If we use a regular HashMap then we will have problems when it gets updated by the ScheduledExecutorService. We can use a synchronized HashMap, but this locks the HashMap and hurts performance during concurrent requests. So I would go with ConcurrentHashMap, which was designed with speed and multithreaded environment. You can safely update a ConcurrentHashMap on separate thread without worry.

If you apply this technique then its still a viable solution for DOS prevention and while supporting per client maxTransmissionRate.

Upvotes: 2

Related Questions