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 userSAME_UID_IP
: limit requests per user at specific IP addressSAME_AUTH_PROPERTY
: limit requests per a particular property in the authentication token. LikeSAME_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.