Thanks for joining me for the second post in the series. In the previous post I discussed what might be the most concerning attack under every platform – injections. The post demonstrated the changes in attack surface when moving from a perimeter-based entry point in traditional monolithic applications to serverless applications. With serverless apps, injection attacks are event-based and originate from a variety of sources.
Here, in the second post of the series I will examine another issue we sometimes face in application security. In serverless architectures, with multiple potential entry points, services, events and triggers and no continuous flow, things can get even more complex. Unlike traditional architectures, serverless functions run in stateless compute containers. This means that there is no one big flow, managed by a server – rather, hundreds of different functions that run separately. Each with a different purpose, triggered from a different event and with no notion of the other moving parts.
As developers, that means that we will need to make sure that each and every resource requires authentication, while attackers will try to look for a forgotten resource, like a public cloud storage, or open APIs. However, external-facing resources should not be the only concern. Let’s examine both.
Broken authentication for external resources is very common and usually deals with brute force attacks, which allows an attacker to guess a user’s credentials using an automated process of trial and error. Insufficient authentication allows an attacker to access a web site containing sensitive content or functions without having to properly authenticate with the web site. Insufficient authentication can also include attacks such as weak password and insecure password recovery process. The good news is that most of these attacks are now handled by the service provider. We no longer have to deal with password management, anti-automation and password recovery flow. Any such attack will encounter a well-experienced, well-equipped defense available by the infrastructure.
Now, the only thing left for us to do is make sure our resources are configured correctly with the authentication and access-controls required. This can easily be done with the identity management services provided by the cloud infrastructure with services such as AWS Cognito, Azure AD, Google Firebase or Auth0 and others. Leaving any external-facing resources without proper authentication controls could lead to a major security breach in our serverless application.
So, can we go to sleep and wait for the next post? No! Things get more complex when internal functionality is not triggered from an end-user request (or any type of event, for that matter) but that somewhere along the full flow of the application there is a resource that could be triggered in a way that will bypass our application authentication schema. Such broken authentication is usually a result of poor design of identity and access controls.
A very simple serverless scenario could be as follows:
1. An authenticated user sends an API request that triggers a bunch of internal flows (the blue area)
2. Part of the flow includes a file uploaded by the user (e.g. image) which is stored in a cloud storage
3. As a typical serverless flow, when a file is uploaded to a cloud storage, it then triggers another function that processes that uploaded file.
4. However, the cloud storage is open and does not required any authentication.
5. A malicious user uploads a file directly to the cloud storage, which triggers an internal function, allowing the attacker to bypass authentication.
So? another file was uploaded. What is the big (security) issue here? To understand the impact we need to first understand the flow(s) we just bypassed. Let’s try to draw the full picture to understand that.
As an example, an application performs canvas printing on uploaded images, submitted by the user via designated mobile app. The application login consists of the following flow:
As we already mentioned, the cloud storage is configured without proper authentication and is open for any user to directly upload to it.
This enables a few attacks. First, and maybe the most obvious, an attacker could use that to manipulate the application execution flow and trigger the image processing function without providing the billing information (bypassing stage C from the list above), right after filling in the shipping information. How? if the storage has open write access to it, attackers can simply use aws cli for that.
But, there is another attack here, bypassing stage D. The application verifies the uploaded file type and filename to ensure no malicious files are uploaded. However, attackers could upload directly to the storage, they can bypass the security control and upload malicious files.
But securing the cloud storage is easy, with a few clicks the public access is no longer available. Now, how can we make sure there is no other broken authentication in our internal resources? Well, there is no way around that – we need to provide authentication designated to our type of resources and flows. Use known secure methods, such as Federated Identity (e.g. SAML, OAuth2, Security Tokens) and make sure to follow security best practices (e.g. encrypted channels, password and key management, client certificate, OTA/2FA).
Protego Labs can not only help you identify unprotected resources but can give you better visibility of your internal application flow. Allowing you to have a clearer picture of which resources are triggered through what event/resource and what are the next steps it takes.
Don’t panic! Get educated by subscribing to this blog series.