Recent Incidents, including the T-Mobile and Honda data breaches have exposed a horrifying reality that not all APIs are created securely. In fact, many can be extremely insecure. It seems like that behind the scenes there lies a dark and overlooked aspect of API Security.
T-Mobile: A Bad Example
T-Mobile has disclosed two data breaches in 2023. The first breach, which was disclosed on January 19, 2023, affected 37 million customers. The attacker exploited a vulnerability in an Application Programming Interface (API) to steal the personal information of customers, including names, phone numbers, email addresses, and account PINs.
The second breach, which was disclosed on June 23, 2023, affected 836 customers. The attacker gained access to the personal information of these customers, including names, phone numbers, and email addresses, by exploiting a vulnerability in T-Mobile's website. T-Mobile has said that neither breach involved the theft of social security numbers, driver's license numbers, or financial account information.
However, both breaches expose affected customers to the risk of identity theft and phishing attacks. T-Mobile has offered affected customers two years of free credit monitoring and identity theft protection.
In addition to the two data breaches in 2023, T-Mobile has also experienced a number of other security incidents in recent years. In 2020, the company's email servers were hacked, and in 2021, hackers gained access to customer proprietary network information (phone numbers, call records). T-Mobile has said that it is taking steps to improve its security, but the company's recent security problems have raised concerns about the safety of customer data.
Honda - Potentially an Even Worse Example!
Here is a summary of the Honda API flaws security incident:
- What happened? Security researcher Eaton Zveare discovered two vulnerabilities in Honda's e-commerce platform for power equipment, marine, lawn & garden. These vulnerabilities allowed anyone to reset the passwords of any account on the platform, and to access the admin panels of all Honda dealers.
- What data was exposed? The password reset vulnerabilities could have exposed customer data such as names, addresses, email addresses, and phone numbers. The admin panel vulnerabilities could have exposed even more sensitive data, such as dealer sales figures, inventory levels, and customer purchase history.
- How did it happen? The vulnerabilities were caused by a lack of access controls on the platform. The password reset API did not require a token or the previous password, and the admin panels were accessible to anyone who knew the user ID of a dealer.
- What has been done to fix the problem? Honda has patched the vulnerabilities and is investigating how they were exploited. The company has also offered affected customers two years of free credit monitoring and identity theft protection.
- The vulnerabilities were discovered in January 2023, but Honda did not disclose them until June 2023.
- The vulnerabilities were present on Honda's Power Equipment Tech Express (PETE) website.
- The vulnerabilities could have been exploited by anyone who knew the email address of a Honda dealer.
- Honda has said that it is taking steps to improve its security.
The Honda API flaws security incident is a reminder of the importance of security for businesses. Businesses need to carefully review their security practices to ensure that they are protecting their customers' data.
I'm sure that the developers who worked on those systems at Honda and T-Mobile. were kept awake after the breaches as they became all too aware that the code was vulnerable. And i'm sure just as much that you're being kept awake by the question "is our API secure?". Often, the answer can be no, it's not. But what we can do is look at a few best practices to help ourselves be as secure as we can be. Some people may even think this article will give them the panacea of the invulnerable API, but let me tell you - it's not! there's much more, but if you're not doing these it's a good place to start.
OWASP (The Open Worldwide Application Security Project), a non-profit foundation, works to improve the security of software, and they provide some key guidelines for adding some security to your API, looking at some key "attack vectors" (yes, technical jargon - it basically means a way a person or automated software can compromise your application).
Injection Attack
An injection attack is a type of security vulnerability that occurs when untrusted or malicious data is inserted into an application or system, leading to unintended behavior. In the context of an API, injection attacks specifically target the input fields of the API. Attackers manipulate the input by inserting malicious code or commands, exploiting vulnerabilities in the system's input validation mechanisms. This can result in unauthorized access, data leakage, or even the complete compromise of the API. Common types of injection attacks include SQL injection, command injection, and code injection.
SQL Injection Attacks
An sql injection attack is a common method of injection attack, and you'll often see attempts at this in the logs if your API is popular enough.
Imagine we have a simple API that takes user input to retrieve data from a database. the API accepts a parameter of Username and uses that to construct the query:
in this code, the username gets passed directly into the query. let's imagine that our attacker wants to see if we're vulnerable. They insert ' OR '1'='1'; -- ' as the username.
Our query becomes compiled now as SELECT * FROM users WHERE username = '' OR '1'='1'; -- '
if we're vulnerable to this, we've just exposed our entire user table. That's terrifying in and of itself - until you realise it's ALSO exposed the credentials of those users (usernames, passwords, emails probably... that's a great starting place - AND they know you're vulnerable, so they can do a lot more).
Command Injection
Command injection is a type of security vulnerability where an attacker manipulates an API's input fields to inject malicious commands that are executed by the underlying operating system. It occurs when user-supplied input is not properly validated or sanitized, allowing an attacker to insert arbitrary commands. The consequences of a successful command injection attack can be severe, as it grants unauthorized access to system resources and potentially compromises the entire system's security.
Imagine our API not only allows users to enter fields for queries, but also for some reason allows them to enter details for commands. Our API also allows users to list the contents of directories.
here's our bad code:
command = request.getParameter("command")
result = executeCommand("ls " + command)
well this seems familiar - and it really should! it's basically the same attack vector, with a slightly different process. an attacker could probe around on your API and work out different endpoints very quickly, so let's take a look at an input that a user could use:
; rm -rf /
ok so this probably won't work - but what it will do is tell them you're vulnerable. our command becomes:
ls ; rm -rf /
that's horrifying - if you're not covering any security on sql injection, or on command injection - please tell me at least you've considered user priviledge protection - because if not, your entire server just got blanked. if you are though, your attacker now has access to some information about your system setup - and knows commands can be run arbitrarily, as well as sql queries.
Code Injection
Code injection is a security vulnerability where an attacker injects malicious code into an API, which gets executed within the application's runtime environment. This type of attack occurs when the API dynamically interprets or executes user-supplied code without sufficient validation or sanitization.
Code injection can lead to unauthorized access, data breaches, or complete system compromise. To prevent code injection, it is crucial to implement strict input validation, sanitize user input, and carefully evaluate the security implications of dynamically executing code.
by now, you've probably got the drill here - so our API is so badly designed, that not only can our attacker run SQL queries, and run system commands - they can also run code on our server!
here's our awful code:
sd$userCode = request.getParameter("code");$result = executePhp(code);
$result = executePhp(code);
our attacker has now worked out you're vulnerable, so they want access to new things - like, oh i don't know, your environment variables. How about they just go with
return(ob_start();var_dump($_SERVER);ob_get_clean());
it's not pretty, but it is sure as hell effective - it's going to return your entire server variable to the front end. as a string. nasty or what?
So, how can we protect ourselves against these types of attacks? well, there's some nice ways that OWASP talk about in their Injection Prevention CheatSheet, most of which are focussed around effectively 1 sentence:
this may be the most important sentence in this blog - your users can't be trusted. so don't trust their input. why? well one of 3 possibilites
if you're trusting your user to use your system right, then you should really really think about looking at improving input sanitation, input verification and input validation. and don't whatever you do - under any circumstances - ever (have I laboured the point enough yet?) allow your users data to go unchecked into the system - because if it is - it's vulnerable to attack, and it doesn't matter how good your code is - something will be wrong.
Cross Site Scripting (XSS)
Our next attack vector is Cross-Site Scripting (XSS) is a type of security vulnerability that occurs when an attacker injects malicious scripts into a trusted website or web application, which are then executed by the victim's browser. This can happen when user-supplied data is not properly sanitized or validated before being displayed on a web page. The injected scripts can be used to steal sensitive information, such as login credentials or personal data, from unsuspecting users or to perform unauthorized actions on behalf of the victim. XSS attacks can be categorized into three main types: stored XSS, reflected XSS, and DOM-based XSS, each targeting different parts of the web application and exploiting various vulnerabilities.
Stored XSS
Stored Cross-Site Scripting (XSS) occurs when an attacker injects malicious code into a website's database or storage system, which is then displayed to other users when they access a particular page. To illustrate this with a real example, let's consider a hypothetical social networking platform.
Imagine there is a comment section on this platform where users can post messages on each other's profiles. The platform allows users to include HTML tags and JavaScript code in their comments for formatting or customization purposes. However, the platform fails to properly sanitize and validate the user-generated content before storing it in the database.
Now, an attacker exploits this vulnerability by posting a comment containing a malicious script, such as <script>malicious code</script>
. The platform, without proper validation, stores this comment in its database.
Later, when another user views the profile with the infected comment, their browser unknowingly executes the injected script. This script could perform various actions, such as stealing the victim's session cookies, redirecting them to a phishing website, or even manipulating the user interface to deceive them into performing unintended actions.
In this scenario, the stored XSS attack occurred due to the platform's failure to properly sanitize and validate user-generated content, allowing the injection of harmful code that persists and affects other users who view the compromised page. Preventing such attacks requires robust input validation, output encoding, and stringent security measures to ensure the safe handling of user-generated content.
Reflected XSS
Reflected Cross-Site Scripting (XSS) is a type of attack where the malicious script is embedded in a URL or other input, and it is reflected back to the user by the web application. To provide a real example, let's consider a fictional online shopping website.
Suppose this website has a search feature that allows users to search for products by entering keywords. The search term is then included in the URL as a parameter, which is subsequently processed by the server and displayed in the search results page. However, the website fails to properly sanitize and validate the user-supplied input before displaying it back to the user.
Now, an attacker crafts a malicious URL that includes a script as part of the search parameter, such as https://www.example.com/search?query=<script>malicious code</script>
. The attacker then tricks a victim into clicking on this URL, perhaps by disguising it as a legitimate link in a phishing email.
When the victim clicks on the malicious link, the web application processes the URL and reflects the script back in the search results page without proper sanitization. As a result, the victim's browser executes the injected script, enabling the attacker to steal sensitive information, such as login credentials, session cookies, or personal data.
In this example, the reflected XSS attack occurred because the website did not adequately sanitize or validate the user-supplied input, allowing the malicious script to be reflected back to users. Preventing such attacks requires implementing robust input validation, output encoding, and proper filtering of user inputs to ensure that no potentially harmful code is executed by the victims' browsers.
Dom-Based XSS
DOM-Based Cross-Site Scripting (XSS) is a type of XSS attack that occurs when the client-side JavaScript manipulates the Document Object Model (DOM) based on user-supplied data in an unsafe manner. To provide a real example, let's consider a hypothetical messaging application.
Suppose this messaging application allows users to send messages to each other, and the messages are displayed in a chat window using JavaScript to dynamically update the DOM. The application includes a feature that allows users to customize the appearance of their messages by specifying a font color in a text input field.
However, the application fails to properly sanitize and validate the user-supplied input before using it to manipulate the DOM. This allows an attacker to exploit this vulnerability by injecting a malicious script into the font color input field.
For example, the attacker enters the following as the font color: <img src="x" onerror="alert('XSS')">
. The application's JavaScript code retrieves the user-supplied font color and directly injects it into the DOM without proper sanitization or encoding.
When the victim opens the chat window and views the attacker's message, the malicious script is executed in the victim's browser. In this case, an alert box displaying the text "XSS" pops up. The attacker could have used more harmful scripts to steal sensitive information or perform other malicious actions.
In this scenario, the DOM-Based XSS attack occurred because the application did not properly sanitize or validate the user-supplied input before dynamically updating the DOM. To prevent such attacks, it is crucial to implement strict input validation, proper output encoding, and secure handling of user-supplied data to prevent the execution of malicious scripts within the client-side JavaScript code.
So how do we protect ourselves against this? Well, again, our friends at OWASP got us covered with their cheatsheet. But it basically is summed up like before - DON'T TRUST USERS! ensure that anything your user puts in your control, sanitize and ensure can't be executed.
Cross Site Request Forgery
CSRF, or Cross-Site Request Forgery, is a type of web vulnerability that allows an attacker to trick a user into unintentionally performing actions on a website without their consent or knowledge. The attack takes advantage of the trust that a website has in a user's browser by forging requests that appear to originate from the user's browser.
Here's a step-by-step explanation of how a CSRF attack works:
The user visits a malicious website controlled by the attacker while being authenticated on a legitimate website (e.g., a social media platform or an online banking site).
The malicious website contains hidden HTML elements or JavaScript code that triggers requests to the legitimate website without the user's knowledge.
The user's browser, unaware of the malicious requests, automatically includes any relevant authentication information, such as session cookies, with the forged requests.
The legitimate website receives the forged requests and processes them as legitimate actions initiated by the user, since they appear to originate from the user's browser.
As a result, the attacker can perform unauthorized actions on the user's behalf, such as changing account settings, making purchases, or initiating fund transfers.
A real-world example of a CSRF exploit involves an online banking application. Let's say a user has logged into their online banking account and is authenticated with a session cookie. Meanwhile, the user unknowingly visits a malicious website controlled by an attacker. The attacker's website contains an HTML form that automatically submits a request to transfer funds from the user's bank account to the attacker's account.
The HTML code on the attacker's website may look like this:
<form action="https://banking.example/transfer" method="POST">
<input type="hidden" name="amount" value="10000" />
<input type="hidden" name="toAccount" value="attacker-account" />
<button type="submit">Click here for a Free Gift!</button>
</form>
When the user clicks on the seemingly innocent "Click here for a Free Gift!" button, their browser sends a request to the legitimate banking website, initiating a fund transfer of $10,000 to the attacker's account. Since the request includes the user's session cookie, the banking website mistakenly treats it as a legitimate request and performs the transfer.
This example illustrates how an attacker can exploit CSRF to trick users into unknowingly performing actions they did not intend to on a trusted website. To prevent CSRF attacks, web applications employ countermeasures such as CSRF tokens, which are unique tokens embedded in forms or requests that verify the authenticity of the request and protect against forgery.
So how do we protect against this? unsurprisingly, OWASP got us here too with this CheatSheet
Authentication and Authorization
Authentication and authorization, when implemented inadequately, can become attack vectors in APIs. Let's explore a real-world example to understand how these vulnerabilities can be exploited.
One common attack vector is known as "API credential theft" or "API key compromise." Many APIs require developers or users to obtain an API key or token to authenticate and authorize their access. However, if these keys are not properly protected, they can be stolen and misused by malicious actors.
A real-world example of this is the Twitter API incident in 2013. In this case, attackers compromised the authentication and authorization mechanisms of the Twitter API. They gained unauthorized access to the company's administrative tools, allowing them to post tweets from high-profile accounts such as those of celebrities and politicians. The attackers exploited a weakness in the authentication process, likely through a spear-phishing attack or by compromising employee credentials.
By gaining access to the API's administrative tools, the attackers bypassed the normal authentication and authorization checks, granting themselves elevated privileges. This allowed them to impersonate legitimate users and post fraudulent tweets, causing widespread chaos and affecting the credibility of the affected accounts.
In this example, the weak authentication mechanism and the lack of proper authorization controls played crucial roles in the attack. The compromised authentication credentials granted unauthorized access to administrative functions, and the inadequate authorization checks failed to prevent the misuse of these privileges.
To mitigate such risks, it is essential to implement strong authentication mechanisms, such as multi-factor authentication, and ensure the secure storage and transmission of API keys or tokens. Additionally, robust authorization controls should be enforced to limit user access to only the necessary resources and actions. Regular security audits and monitoring can help detect and respond to any potential vulnerabilities or suspicious activities in the API's authentication and authorization processes.
By addressing these weaknesses, organizations can strengthen the security of their APIs, reducing the likelihood of unauthorized access, data breaches, and the misuse of privileged functions.
Luckily, our friends at OWASP got us covered once again with their cheatsheet. there's lots of good info in there. Its often forgotten as an attack vector, but our systems can be vulnerable if we're not securing our Auth flows nicely.
Secure By Design
so we've seen a few different attack routes here - and a few ways we can combat them - but we can actually be secure by design from the ground up. When planning our API's, security should be a key feature of our consideration process, and should be pretty much at the forefront of everything we do. There's a REST Security Cheat Sheet (suprise! OWASP do everything!) that gives you a good starting place, but honestly consider every single thing that comes in and every single thing that goes out of your API.
I often ask myself, when I'm designing API's the following questions:
By thinking about these from the ground up, I often find i'm putting myself in the shoes of both a user, and a bad actor, to consider every single step of my API, and then how different endpoints can be abused together to get more info.
OWASP start us off with some great best practice guidelines to adhere to, and I would strongly commend them to anyone starting off an API, so go browse around their CheatSheets (I've linked several throughout this article). It's also worth a look at the OWASP Top Ten Project to get more on the top ten security risks.