11

To avoid abuse I'd like to add rate limiting to the REST API in our Rails application. After doing a bit of research into this it looks like the best practice is to move this responsibility into the web server rather than checking for this in the application itself. Unfortunately this can't be done in my case as I'm hosting the application on Heroku and so have no control over the web server set up.

What should be done in this case to stop abuse of the API?

Community
  • 1
  • 1
xoebus
  • 812
  • 7
  • 18
  • 1
    Hm, you could hack a solution together (though it'd be ugly), depending on how large your responses are. For example, if your responses are small (<1 MB for the responses you want to limit), you could setup a timer where repeat requests from a given session are limited/delayed based on the action you're performing. If instead, your responses are large, this will only space out the replies (as opposed to slowing down the rate of transfer). – jefflunt Jun 21 '11 at 22:16
  • @normalocity Hmm, I'm quite liking this idea! I don't think it would be that ugly with a simple before_filter on the vulnerable controllers. Adding more complex rules could become more complex though (e.g. 10 requests per minute per user). – xoebus Jun 21 '11 at 22:56
  • Huh - well maybe I'll submit it as an answer then. :) Maybe add a field to the user account that notes last time they made a request. The tricky thing is, if you're using Mongrel (or another single-threaded web server) if you simply delay the request you'll slow down everyone else. I guess that's what I meant by ugly. If you're using a different web server maybe this approach would work. – jefflunt Jun 22 '11 at 02:22
  • Have you asked the Heroku staff for help? It would be in their interest to help you with this since abuse would negatively affect their platform. I've found them to be pretty helpful. – Andrew Jun 22 '11 at 02:38
  • 2
    Abuse of an individual application, in a manner that the individual application might categorize as abuse as described in the question, would not negatively affect the Heroku platform, since the Heroku platform is (seemingly) infinitely scalable and Heroku practices utility pricing. – yfeldblum Jun 22 '11 at 05:28

2 Answers2

1

I think what you are looking for is the rack-throttle or rack-attack gem. Both of them allow throttling and the rack-attack gem also allows you to time people out for a certain period of time and block certain IP addresses if they are multiple time offenders or for whatever other reason you would want to block requesters.

Billy Ferguson
  • 1,429
  • 11
  • 23
0

Consider putting a cookie on the client, or better yet, a field on the user account that records the last time they made a request (many authentication plugins do this already), and simply reject/delay their request if it's more recent than, say, 5 seconds ago (20 requests/second).

NOTE: If using a single-threaded web server (e.g. Mongrel) putting in an explicit delay rather than a rejection might delay other pending request on that Mongrel. In other words, it's going to impact your other users. Maybe a small javascript/ajax response to notify the user that they are being rate limited, if that is appropriate. Think how StackOverflow prevents you from doing certain things too often on the site.

jefflunt
  • 33,527
  • 7
  • 88
  • 126
  • 1
    Ended up putting a field in the "user" account (doesn't directly translate in this case) with the time of the last request. (As an aside: since privacy is a concern with this application we used Redis to store this information and [EXPIRE](http://redis.io/commands/expire) the keys after a short period of time.) – xoebus Jun 22 '11 at 12:56
  • 4
    This answer is dangerous and wrong. "Putting a cookie on the client" does literally nothing to rate-limit an attacker/abuser. Putting a timestamp on the user object both a) prevents a user from making two legitimate requests in a row (slowing down your app) and b) does nothing to rate-limit the most important API endpoint: authentication. If you aren't rate-limiting unauthenticated requests, anyone that can write a script can easily bruteforce your users' passwords. You want to rate limit by IP address instead, with stricter limits on the authentication endpoints. – fletom Sep 09 '14 at 15:57
  • @fletom - You're right (looking back 3 years ago now). This is a much better solution. If you want to writeup an answer I'll happily delete mine and upvote yours. – jefflunt Sep 10 '14 at 01:47
  • This doesn't really answer the question. – superluminary Jun 12 '15 at 15:45