Software today is more decentralised than it's ever been, with apps functioning as distributed microservices instead of a single monolithic block of code. APIs (Application Programming Interface) are the bridges connecting these apps together, allowing them to 'talk' to each other.
But as you can imagine, unrestricted flow of information between apps is a recipe for disaster, particularly when you're dealing with user data. API Security is what stops someone from intercepting that communication between two apps and capturing data they weren't supposed to access.
Think of it like patching up the leaks in a pipe...except way more complicated. APIs by their very nature expose application logic and sensitive data, and this makes them a prime target for cyberattacks.
Regularly testing and identifying vulnerabilities in your APIs (particularly if your app is divided into multiple microservices) isn't just a good practice, it's absolutely essential for ensuring the security of your software.
That's why we've created this handy guide on what you need to know about API security in 2021. This article accompanies the release of our newest course on API Security: Attack and Defense, which is part of the Advanced Application Security Learning Path.
No talk of software vulnerabilities is complete without mentioning the OWASP Top 10. Thankfully, they've made a special Top 10 list for API security vulnerabilities, which should also tell you how big of a deal they are. Some of these you might recognise from the main OWASP Top 10 list, but most of them are specific to APIs.
Here are the 10 most critical API security vulnerabilities according to OWASP:
Object level authorization is an access control mechanism that ensures only valid users can access objects or data that they have the authority to access.
BOLA vulnerabilities are a result of the failures of these control mechanisms, and allow the attacker to view or modify sensitive data they shouldn't be able to see. Once found in an app, a BOLA vulnerability can be easily exploited.
As the top vulnerability on this list, BOLA is the highest priority flaw that developers should focus on fixing. The best way to prevent it is by identifying users through access tokens or others types of secrets, and implement access control on sensitive API endpoints that require some privilege. Alternatively, use random IDs (UUIDs) to enforce access control.
Web apps use sessions and credentials to manage authentication and access control. Broken authentication is an umbrella term referring to a number of vulnerabilities that allow attackers to exploit session or credentials management.
By hijacking session IDs and stealing login credentials, they can impersonate legitimate users and gain access to sensitive user data online.
Preventing broken authentication vulnerabilities is a rather involved process. You need to ensure you're enforcing access control for all sensitive data and functionalities. Use short-lived access tokens that are long, random, complicated strings.
Tokens derived from user information should use strong algorithms and secret keys to stop users generating their own tokens. Finally, treat access tokens as secrets and never send them over unencrypted channels.
Let's look at a typical API use case: a user needs to access their information on a web application. To get it, the app requests data from the API service, which returns the user's data to be displayed on the webpage.
This API call may contain sensitive personal information, and if the API client application doesn't filter it before sending the data to the user, it could be revealing unnecessary amounts of data. Excessive data exposure happens when the client application doesn't filter the results it receives from the API, showing the user information they weren't meant to see.
The first step to prevent this vulnerability is clear: your app should filter any sensitive data it receives from the API service before sending it to the user. Determine what your user should and shouldn't know, and ensure the filter keeps out any information the user shouldn't have access to. You should ideally be displaying the minimum amount of information possible on the webpage.
Additionally, if the API allows it, you can request the minimum amount of data needed from the server. For instance, GraphQL APIs allow you to specify the exact object fields you need in an API request. Finally, avoid sending sensitive data over unencrypted channels.
When an API doesn't restrict the number of requests from a client application, it can allow an attacker to make thousands of API calls per second, overloading the server with more requests than it can handle.
This can result in a severe hit to the server's performance and allow attackers to launch Denial of Service (DoS) attacks. Apps without rate limiting can also allow malicious actors to attempt brute-force attacks on authentication endpoints.
Preventing these issues is all about context, since the rate and resource limits for each functionality needs to be different. For example, the rate limit for authentication endpoints needs to be much lower to prevent brute-forcing and password guessing attacks.
You should first determine what 'normal' usage for that function, at which point you can block users who request resources at a much higher rater than usual.
Broken function level authorization is similar to BOLA in that both vulnerabilities allow attackers access to resources they should otherwise not have access to. However, it differs from the latter in that it applies not to objects, but to functions in the application.
For example, a user being able to modify another user's account, or a regular user accessing admin functionality on a website. Broken function level authorization is usually the result of some missing or misconfigured access controls.
The most straightforward ways to prevent BFLA are by restrict and properly enforce admin privileges, and denying access to functions by default. Only allow operations to users who belong to a specific group or role. As a broader note, ensure that you properly design and test authorisation on your apps.
It's quite common for applications to automatically assign user input to program variables and objects in order to simplify app development.
For instance, a website might allow you to change your username with a simple request. However, if a malicious actor sent another similar request to elevate their user privileges, which let them become an admin, it could have disastrous consequences.
To prevent mass assignment, here's a few things you can do. Don't automatically bind incoming data and internal objects, and explicitly define all parameters and payloads you're expecting. In addition, precisely define the schemas, types, and patterns you'll accept in requests at design time, and enforce them at runtime.
Security misconfigurations are an extremely common threat both to API and non-API apps. This term refers to all manner of insecure configurations that inadvertently introduce a host of security issues and weaknesses.
The most common misconfigurations include unsecure default configurations, incomplete or ad-hoc configurations, open cloud storage, misconfigured HTTP headers, unnecessary HTTP methods, permissive Cross-Origin resource sharing (CORS), and verbose error messages containing sensitive information.
But security misconfigurations can be prevented by following a few best practices. Streamline your bug fixing workflow by establishing repeatable hardening and patching processes, as well as automating the process of locating configuration flaws.
You should also restrict admin access to users and disable unnecessary features that would just cause more harm than good. And finally, you should strictly define and enforce all outputs, including errors.
Injection is currently the most critical vulnerability at the top of the OWASP Top 10, and continues to be a serious flaw in API security as well. Injection vulnerabilities occur when the application can't distinguish between untrusted user data and code.
If the application doesn't properly process the untrusted user data before inserting it into a command or query, the program could misinterpret the data as part of the command. An attacker can send data that contains code that manipulates system logic, and thus trick the app into executing those commands and giving them what they want.
Injections can be extremely tricky and difficult to prevent, because even if the injected data isn't harmful right away, it could travel somewhere in the program where it can do damage. The most important first step is to validate all incoming data from the user, implementing a blocklist that will block any dangerous characters that could compromise parts of your app.
Alternatively, use an allowlist that will only allow certain characters and strings that you know to be safe. You need to strictly define all input data, such as types, string patterns, schemas, etc. and enforce them at runtime.
If these options are too restrictive, you can try parameterization: compiling the code part of a command before any user-supplied parameters are inserted. That way, your app will be able to distinguish between the code and user input, no matter what the latter looks like.
There's one more option called escaping. This refers to a technique where you encode special characters in user input, so that they're treated as data rather than special characters. This lets the interpreter know the data isn't meant to be executed.
Improper assets management is typically a problem born out of human error or lack of organisation. By allowing older APIs to remain in place without replacing them with newer, more secure versions, it opens up many more access points that could be insecure.
With the growing popularity of microservices and cloud, it's become common practice to spin up a new service temporarily. Rather than being decommissioned, if the older APIs are left connected to the production environment, it could pose a huge security risk.
The most important (and easiest) thing you can do to mitigate this is to keep a constantly updated inventory of all API hosts. This will ensure you keep track of old versions of APIs that you can retire once they become obsolete, or backport security fixes to them.
In addition, simply limiting access to anything that shouldn't be public, as well as limiting access to production data can make a big difference.
Exploiting an application can be quite a time-consuming and involved process, and doesn't just happen over the course of a few hours or days. Once an attacker gains a certain level of access into the app, they will attempt to further explore possibilities to exploit more vulnerabilities within the software.
The only way to detect and find such an individual would be to implement a robust logging and monitoring system capable of identifying malicious activity as soon as possible.
Organisations often only log infrastructure like server logins and network events, while ignoring APIs and application-specific infrastructure. API logging is a necessary component of a monitoring system, in order to keep track of abnormal API usage.
Infosec expert Vickie Li says, "You can log events like input validation failures, authentication and authorisation successes and failures, application errors, and any other API events that deals with sensitive functionality like payment, account settings, and so on."
Over time, you'll start to understand what normal API activity and usage looks like, and suspicious activity will become easier to detect.
But there's a ton more to learn about APIs! That's why we've launched a brand-new course on attacking and defending against vulnerabilities in API security. This course is packed with hands-on labs, easy-to-follow video lessons, and more! Check it out in the link below.
Aneesh Bhargav is the Head of Content Strategy at AppSecEngineer. He has experience in creating long-form written content, copywriting, producing Youtube videos and promotional content. Aneesh has experience working in Application Security industry both as a writer and a marketer, and has hosted booths at globally recognized conferences like Black Hat. He has also assisted the lead trainer at a sold-out DevSecOps training at Black Hat. An avid reader and learner, Aneesh spends much of his time learning not just about the security industry, but the global economy, which directly informs his content strategy at AppSecEngineer. When he's not creating AppSec-related content, he's probably playing video games.