As a backend PHP developer and a security consultant, the only thing that terrifies me more than a SPA on top of a stateless API is a mobile app!
Authentication (and authorization) in a traditional PHP app is relatively easy: give the user a secure cookie and store whatever information you need in the session. Each request includes the cookie, the state is automatically across requests through the session, and nothing is exposed to the user.
Upgrading to an SPA on top of a stateless API adds an extra layer of complexity to the mix. Your SPA needs to collect user credentials, send those to the server, retrieve some tokens, and then send that with every future request to the API. With the right tools, it’s not that hard to get working, and it’s easy to shift much of the hard or sensitive work into the API. The mental separation between SPA and API is relatively easy - and because SPAs are javascript in the browser, you’re already considering the security implications. For more on API security challenges, see this article.
Mobile Apps, on the other hand… scare me.
To demonstrate why, let’s take a look at some “bank-grade security”!
“Bank-grade Security”?
When considering banking websites and apps, consider “bank-grade security” and set your expectations high. After all, banks need to protect their customers' money, right?
So, when they build mobile apps, they naturally make them super secure… right? Check out some lessons learned from API security incidents here.
Well…
In 2021, Alissa Knight and Noname Security published research they did into mobile banking apps, which revealed some rather interesting findings. They reviewed 55 different banking apps, looking for common vulnerabilities and weaknesses in mobile apps, and the results were pretty shocking.
Almost all (54 out of 55) included hardcoded API keys in the mobile app.
All were vulnerable to Person-In-The-Middle (PITM) attacks.
All were vulnerable to Broken Object Level Authorization (BOLA) attacks.
All were vulnerable to other authentication vulnerabilities…
Let’s dig into these findings and determine where they went wrong.
Hardcoded API Keys
Traditional server-side applications store their API keys on the server, where an attacker cannot access them. The user is typically authenticated and authorized through a session cookie, which remembers who they are and is stored within the browser. Thus, there is no direct API or need for first-party keys, and any third-party API interactions are performed on the server, so the user never sees the keys.
SPAs typically feature some form of header token, which the server generates and shares with the API when the session is initiated, so nothing is hardcoded in the SPA in the browser. Even if these SPAs need to interact with third-party APIs, they’ll either proxy through their own API—to keep the keys protected on the server—or they’ll include special public keys that are designed to be used in the browser directly and don’t pose a security risk.
But mobile apps pose a problem. The app isn’t running directly on the server or from a recently downloaded JavaScript payload in the browser on a controlled domain. Mobile apps run independently on the devices they are installed on.
This clear separation encourages mobile app developers to shift as much of the work as possible into the mobile app, which includes interacting with APIs—both their own and from third parties. However, interacting with these APIs requires keys, and it’s really easy to see how a developer might think compiling an app makes the contents—and any keys it includes—unreadable.
Some tools, such as one aptly called “strings,” extract all of the raw string values from a compiled file. All attackers (or security researchers) must obtain the compiled app file (which is also easy) and then run these tools on the apps. It’ll spit out any API keys contained within the files.
As a side note, banking apps are not the only ones that suffer from this. Kevin Watkins from security company Symantec released a report in September 2022 in which they analyzed over two thousand mobile apps on both Android and iOS, looking for hard-coded AWS credentials.
Of the apps analyzed, over three-quarters included valid private AWS access tokens, while almost half of those tokens gave access to private files in Amazon S3! They dug into this a lot further, so I’d suggest checking out the full report if you have the time. However, the point I’m trying to make here is that it’s common for mobile apps to include hard-coded API keys. Read more about avoiding hard-coded API keys here.
Intercepting Requests
The next finding in Alissa Knight's research was that all of the apps tested were completely vulnerable to person-in-the-middle (PITM) attacks. This allowed her to intercept and decrypt the traffic between the banking apps and their APIs.
The risks here are twofold:
Firstly, if an attacker can intercept and read API requests, they can use the app within a controlled environment, extract any keys, and map out the app's API. This can then be used to perform attacks and manipulate data, looking for vulnerabilities and weaknesses in the API.
Secondly, if someone uses these banking apps on an unprotected network, an attacker may be able to intercept the victim’s requests and read sensitive information, such as their bank details, balance, etc. The app may also allow the attacker to modify or forge requests, opening the door for the attacker to transfer money out of the victim’s bank account.
These risks highlight the need to secure API requests using multiple layers of protection properly.
The first step is to require HTTPS on all API requests, with a valid certificate that matches the API hostname. This ensures that the mobile app and the device itself will only trust legitimate HTTPS certificates, preventing opportunistic attacks on unsecured networks. There is still a risk of adding a malicious certificate to the device, but that requires a much more targeted and sophisticated attack.
These vulnerabilities often occur in mobile apps because it’s common for developers to disable certificate verification for dev and testing, to avoid needing to toggle hostnames and set up local HTTPS. However, I believe the risks of disabling certificate verification far outweigh the benefits of making the developers' lives a little bit easier! For an in-depth guide on API security, check this article.
The next layer looks at some form of manipulation prevention for API requests. This is commonly done using a checksum on the payload, which is verified before the API request is processed. Ideally, this should be performed on both sides - so that both the client and the server verify the request is unmodified before processing it. This will prevent an attacker from intercepting a request and changing some numbers - such as redirecting payments from one bank account to another.
It is also important to include some record of time and expiry into API requests, to prevent Replay Attacks. These are attacks where an attacker records legitimate requests and then repeats them at a later point. This can be used to manipulate user data and sometimes as part of a wider attack chain. Any requests made outside the window can be simply ignored by including a timestamp and having a limited expiry window. These values should also be included within the checksum to prevent them from being manipulated!
Broken Authentication & Authorization
These findings aren’t mobile app-specific but rather occur in all types of APIs, and basically mean that the API isn’t correctly checking who the user is and if they are allowed to do what they are attempting to do. In fact, it’s not even limited to APIs - it’s just a common vulnerability that occurs in any sort of application. Read more on API breaches and their consequences here.
If we check out the OWASP API Security Top 10 for 2023, here are all the risks that relate to this topic in some way:
API1:2023 - Broken Object Level Authorization
API2:2023 - Broken Authentication
API3:2023 - Broken Object Property Level Authorization
API5:2023 - Broken Function Level Authorization
Yep, 4 of the top 5 are different flavors of this issue.
And if we check out the OWASP Web Application Security Top 10 for 2021:
A01:2021-Broken Access Control
A07:2021-Identification and Authentication Failures
Still got the top spot, plus #7.
This is clearly a common problem, given its prevalence in OWASP’s Top 10 lists. In my experience as a penetration tester, it comes down to developers not considering authentication and authorization when writing their code. Learn more about API security tools that can help avoid these issues.
It’s so easy to get caught up in the business logic, what data needs to go in, and what data needs to go out that it’s easy to overlook the question: is this user allowed to access this data?
I think this also comes down to using decent frameworks and tooling. If you build your apps with a solid authentication and authorization system - something that ensures requests are only made by active users before your business logic kicks in and provides a really easy way to check does this user have access to this resource
, developers are more likely to consider and use it when building features.
Avoiding These Vulnerabilities
While the goal is for developers not to write insecure code, I know firsthand that it’s easy to overlook subtle weaknesses and introduce vulnerabilities in code. As such, we really need to put protections and checks in place to help identify issues as they arise.
As I mentioned above, building out solid authentication - OAuth 2.0 with OKCE (Proof Key for Code Exchange) is a good place to start for authenticating users and implementing solid authorization checks within your API. Follow these up with automated tests that check permissions (this is something many devs overlook!).
Secondly, run some automated tools like TruffleHog against your codebase. Trufflehog is one of my favorite tools, and it looks for committed API keys, secrets, and passwords within your code. It’s fantastic at picking up things like AWS keys, so if your mobile app accidentally contains API keys, there is a good chance it’ll find them. If it’s hooked into your build and compile process, it’ll alert you for any secrets that find their way in before your code is deployed and released.
Thirdly, some API monitoring, visibility, and auditing should be implemented. If you know what’s going on with your APIs and your users' requests, you’ll be better able to spot attacks and malicious behavior and investigate - before someone abuses it! Treblle can help with this step. 🙂
Summary
Mobile apps present a unique security challenge you need to be aware of. Never forget that your users have full control over your mobile app and, thus, your API. Everything the app has access to do, your users do as well. So make sure you lock it down so the mobile app has the same powers your users should.
💡
Start optimizing your API performance today with Treblle. Experience the benefits of real-time monitoring, comprehensive logging, and actionable insights. See how Treblle can enhance your API observability and help you maintain robust and reliable APIs!