Securing APIs: How to Design a Not So crAPI One
In this post we discuss about some components that every API should have in order to not build a Completely Ridiculous API (A.k.a crAPI).
You cannot longer afford to build crAPI ones
It’s no secret that APIs are becoming more popular because of initiatives such as Open Banking (PSD2) and IoT. This means that data is being exposed, and while some of it might be meant to be public, sensitive data such as PII (Personal Identifiable Information) is also being served. As a result, these initiatives need to take a secure approach since data breaches are becoming more common. Similarly, regulations such as GDPR are making sure the companies that are leading these initiatives are being held accountable, thus designing a secure API (and every other piece of software in general) has become both: A critical business and technical need.
Getting Started
One way to build a not so crAPI API is by adding security layers. Each one of them will provide a specific control that will make it harder for an attacker to compromise the application. One way an attacker can do so is by taking advantage of the following:
- Spoofing
- Tampering
- Repudiation
- Information disclosure (privacy breach or data leak)
- Denial of service
- Elevation of privilege
These set of threats are often referred as STRIDE, a model used to help reason and find threats to a system. Today you will use this model to harden your application.
The Authenticator Layer
Imagine that you receive an invitation to a wedding. When you arrive to the event, you go to the entrance and show your invitation and you use your name to get in. Then, you go inside and you have a seat, a 3-course meal, and you can ask the waiter for drinks. Once inside no one will ask for your invitation, because that already happened at the entrance and you are going to be treated as an invited guest.
Just as you don’t want uninvited people in a wedding that is supposed to be for close friends and family, you don’t want unauthenticated (uninvited) users consuming resources that are meant for authenticated (invited) users. As a result, you need to make sure that authenticated requests are the only ones that are processed. If you receive an unauthenticated one, it should be ignored by the system.
“Protecting each API endpoint behind authentication requirements should be the norm. Don’t allow free passes on a resource unless necessary for functionality.”
In order to do so, the authenticator needs to be able to ensure that users and clients are who they say they are. This process involves at least one of the following three things:
- Something that you know (e.g. Password)
- Something that you have (e.g. Your phone)
- Something that you are (e.g. Your fingerprint)
To be able to authenticate users in an interoperable and manageable way, you can rely on protocols such as OAuth2, OpenID Connect, and JWT. Using one of these solutions will also give you the possibility to manage aspects of user identity such as log in, sign up, logout, and more.
The Access Controller Layer
Now that you have the authenticator in place, let’s go back to the previous wedding example: After enjoying the event for a while, you go to the toilet and you pass by the bar. Then you see a really fancy wine bottle. You ask the waiter for one glass, but she politely tells you that the bottle is only meant for the family of the bride. In other words, not because you are already inside means that you can do anything you want. As a result, you need to add a second component: The Access Controller.
This component will allow you to identify, not who, but which permissions or claims the user that is making the request has (Remember: authentication != authorization).
In addition, the Access Controller will help to preserve confidentiality and integrity within the system. How? Data will only be accessed and modified by users that have the necessary claims to do so. One way to represent claims securely between two parties is by using a JSON Web Token (JWT). This is an open, industry standard RFC 7519 to manage authorization.
P.S. Because the JWT could be leaked, remember to add an expiration time claim that meets your business needs and to use a strong secret.
The Rate Limiter Layer
For every piece of software out there (even if it is in the cloud), there is a physical server plugged somewhere. This server has limitations such as memory and CPU. As a result, you want to make sure that no one is overusing those resources, because this would mean that it would be at the expense of other legit clients. One way to prevent this is to add a Rate Limiter Layer. As its name suggests, this component indicates how many calls your application may make per time window. Adding this layer of protection will also help to slow down brute force attacks (e.g. login endpoint) and to protect the overall availability of the system.
To implement this solution, you can introduce a rate limiter application middleware or you can delegate the rate limiting duties to a load balancer such as NGINX. This is done by a rate limiting algorithm (e.g. Leaky Bucket) used to check if the user session (or IP address) has to be limited based on the information in the session cache.
Although it would be possible for client X to use different IPs to ‘fool’ the Rate Limiter, you need to remember that there is dollar cost of each legit IP. So it’s up to the attacker to decide whether it’s worth the money to obtain a bunch of different IPs or not.
The Logger Layer
Where are the logs? This question is probably going to be the first one asked by Law Enforcement or Compliance as soon as there is a security incident or an audit. Having a Logger (Audit System) will allow you to take a break when this happens. Furthermore, it will give you an understanding of what is going on. For example, questions such as who is making the API call, which type of request is it, and from where is that call coming from are going to be easily answered.
Besides, a good Audit System will allow you to create alerts that will help you to respond accordingly (and hopefully in time) if something bad happens. In addition, you need to ensure that every authenticated request (even though it is not authorized) goes through the Logger layer. By doing this, you are going to be able to identify if Alice, an authenticated client, is trying to access Bob’s private resources or if she is making calls to unauthorized endpoints.
Failing to have a good Audit System will make Forensic Evidence and Long Term Analysis really difficult. According to the OWASP, most breach studies demonstrate the time to detect a breach is over 200 days, typically detected by external parties rather than internal processes or monitoring.
Wrapping it Up
After adding the Authenticator, Access Controller, Rate Limiter, and the Logger, you have been able to mitigate some of the STRIDE threats discussed at the beginning of this post.
Spoofing now is less likely, because you have an authenticator in place to be able to differentiate between Alice and an unauthenticated user. And because you know that Alice is supposed to only read and modify her own data, Information Disclosure and Tampering are more difficult to exploit since you have an Access Controller in place. And not only that, if someone is trying to maliciously modify data, you (and the CISO) can sleep better since the Logger will be able to identify who is making the malicious call without the risk of someone denying or repudiating it. Last but not least, if an attacker wants to cause a Denial of Service (DoS) attack or brute force a specific endpoint, she will have a hard time doing so since the rate limiter is up and running.
Final Thoughts
This was just an overview of some components that should be taken into account when designing an API. You can always add breadth and depth to this implementation. However, omitting or misconfiguring one of these layers could lead to a security incident or fail to respond and learn from one. Remember, nothing is un-hackable, but you can make your API a real pain in the arse to be compromised.
P.S. If you want to go deeper into secure API design, I highly recommend having a look at the OWASP API Security Project.
Resources
Originally published on Medium.