API Security – Preventing Abuse of API Called via Client-Side JavaScript

apiArchitectureawscachinglambda

I'm setting up an AWS API Gateway + Lambda micro-service that will return non-sensitive but user-specific data.This means that the responses from the service can't be cached and served to multiple users.

There is a possibility that unauthorized third parties will hit this service and cause large spikes in resource usage.

Why does it have to be a client side request?

Pages on the main website are usually cached and served from CloudFront without sending each request to the origin server so it is impossible to make this request server-side for each user.

Ideas I've Had

  1. Requiring an API key to be used to access the service.

    This is unlikely to be the magic bullet because even if the key itself is hidden by making a call to a separate back-end script, all an unauthorized user would have to do is call the script instead of the API directly and they would get the same results.

  2. Adding custom checks based on headers, origin etc. before sending a valid response from the API

    These things can be spoofed relatively easily so it's by no means guaranteed to work but it might deter a lot of less motivated people.

Is there anything else that can be done to ensure that this service is only accessed by people actually viewing the website and not third party applications?

Best Answer

In this case, i would add various kinds and combinations of rate-limiting, e.g.:

  • maximum requests per interval allowed for the complete API
  • maximum requests per interval for specific parts of the API, if you have certain calls that are 'expensive'

If you are able to identify non-authenticated calls, e.g. by IP-Adress or Cookies or something, you may be able to additionally limit that even more accurate. E.g.:

  • maximum requests per client per interval for complete API
  • maximum requests per client per interval for specifica parts of the API

Interval could be anything, e.g. hardcoded 5 seconds, in a fixed or a sliding time window.

In one project I implemented something like that using a combination of ip-adress and if available the user-id, and it worked very well - protecting the service from misuse/attacks of anonymous, identifiable and even properly authorized clients.

Iirc I used https://github.com/mokies/ratelimitj - the readme there also points to some background articles, e.g. https://blog.figma.com/an-alternative-approach-to-rate-limiting-f8a06cf7c94c

Related Topic