I was digging around trying to find some means to do rate limiting on Firebase references. I found this answer on StackOverflow that describes a method to do it.

At first blush, I assumed this only works for a client that respects the rules and writes to last_message faithfully. So, I prematurely commented and Tweeted that this only works for "benevolent" clients. After picking through the rules and the sample Fiddle, I see that I'm wrong. Kato has this covered.

However, that's a lot of work. What if I have 5 or 10 references that I want rate limited? Then, my last_message reference has to become something like rate_limiting with a reference for last_message, last_this, last_that.

Then, my rules become something like:

".validate": "newData.val() >= now - 500 && newData.val() === data.parent().parent().parent().child('rate_limiting/last_message/'+auth.uid).val()"

or

".validate": "newData.val() >= now - 500 && newData.val() === data.parent().parent().parent().child('rate_limiting/last_this/'+auth.uid).val()"

or 

".validate": "newData.val() >= now - 500 && newData.val() === data.parent().parent().parent().child('rate_limiting/last_that/'+auth.uid).val()"

... times X for all references that need limiting

As I said a lot of work and validating and checking etc.

Feature Proposal

I'd like to propose something like this:

"messages" : {
  ".rateLimits" : "SAME_IP.interval() > 500 && ALL_IPS.perSecond() > 100"
  ".validate" : "your usual validation rules go here"
}

The new rateLimits property would take care of all rate limiting in one spot. The SAME_IP.interval() rule would restrict any write requests from a single IP address to no faster than every 500ms. That way, one IP address couldn't flood your reference with junk. The ALL_IPS.perSecond() rule would prevent writing to a reference if more than 100 in a second were attempted for ALL IP addresses.

There could be several types of rate limiting methods like:

  • SAME_UID : limit requests per user
  • SAME_UID_IP : limit requests per user at specific IP address
  • SAME_AUTH_PROPERTY : limit requests per a particular property in the authentication token. Like SAME_AUTH_PROPERTY('account').interval() > 500

Of course, this proposed .rateLimits option is a big departure from the ".validate" option. So in a less ideal world, maybe these new options could be put in .validate.

"messages" : {
  ".validate" : "RATE_LIMIT_SAME_IP.interval() > 500 && RATE_LIMIT_ALL_IPS.perSecond() > 100 && the_rest_of_your_validation_rules_go_here"
}

What do you think? If it seems like a good idea, let me and the folks at Firebase now.