I am building a REST API and intent to use rate limiting (using the leaky bucket algorithm) as a way to protect against crawling and enumeration. The API will be consumed by a Mobile/Tablet App (installed on many devices) and server-to-server clients (some in-house, some external).
Allowing users to install the app on their phones (factually rendering the data exposed by the API public knowledge) while still limiting crawling and enumeration by reverse-engineers i've come up with this strategy:
- On first run, the app generates a random ID large enough to be considered unique
- When requesting a token for API access the app authenticates with that ID.
- Any token request for the same app ID is answered with the same token (as long as it hasn't expired)
- Any token request for the same IP address is answered with the same token (as long as it hasn't expired), entirely ignoring the app ID.
This policy does not apply to the server-to-server clients as those will have to set up a contract with my company in order to consume the API.
Now, as to rate limiting:
Is one of these strategies preferable? If: what are the pros and con's?
- assure no consuming entity gets hold of more than one valid token at a time (basically the same as with the APPs). Hook the leaky bucket to the tokens.
- grant as many tokens to an entity as it requests. Share the leaky bucket across all the tokens granted to an entity.
Also: If option 1 is preferable: How should the 1-token-per-entity policy be applied?
- Grant new tokens only after previous ones have expired. Provide an interface allowing entities to revoke/invalidate their current token.
- When a new token is requested revoke all previous tokens.
I am especially worried about race conditions between
- multiple server instances of the same contractor (thus all subject to the same rate-limit)
- multiple app installations running sharing an IP address (public WiFi, multiple users sharing an internet connection, ...)