At eCloudValley Philippines, we prefer developing web backends as serverless applications. We just push the code to AWS and they worry about the infrastructure. We don't have to think about provisioning, patching, scaling and securing it. That's all AWS. In terms of security, since even us don't have access to the infrastructure, we don't have to worry about it. We pay AWS to worry about that for us. But what we do have access to is the code. And that's one major attack vector we have to secure. And in ECVPH, we take that very seriously.
In this article, we will take a deeper look at how Serverless workloads get hacked, and what you can do about it.
Here are the 6 common types of attacks on Serverless applications
[1] Denial of Service
You'd think Serverless applications don't get DDoS attacks. Yes, they can scale fast. But the network components attached to them don't often scale at the same rate as them. We've seen Lambda functions use an RDS database, or is connected to an API that is deployed on a traditional EC2 setup. Your lambda functions will scale to meet the traffic, but they will rain down traffic into these weaker downstream dependencies.
That's why it's often a good idea to do event-driven architecture. Instead of directly writing into the database or directly calling the legacy system, the Lambda function queues
It's not only infrastructure that can cause denial of service. Sometimes, there are vulnerabilities in your packages that can cause this. For example, this Python package for etherium can cause resource exhaustion when a specific payload is added to it. With just a few requests, the package causes a malfunction that causes it to hog all the CPU and RAM of the device. This exhausts the resources of the server, causing it to go down.
To learn more about how to survive a DDoS attack, check out my blog post about how we survived a 2M requests per min attack.
[2] Denial of Wallet
But suppose that somehow your entire setup is serverless. You're using AWS Lambda for your compute, DynamoDB for your backend, and S3 for all your files. The attacker can just keep attacking you and AWS will be able to keep your website up. But since these services are pay-per-use, you'd just end up racking up higher AWS charges. And so long as they can sustain their attack, they can bankrupt your company to the ground.
To protect against both DoS and DoW attacks, it is best to put into place some kind of rate limiting. AWS WAF does this by allowing you to limit request per second for each IP address. This makes these attacks harder, but not impossible, especially if they have thousands of IP addresses on their disposal.
[3] Remote Code Execution
While the most common attacks are volumetric in nature, some just need a few API calls and they've compromised your system. The most common of which is remote code execution. It is when hackers are able to manipulate the payload so that they can execute custom code in your application.
Probably the most insecure code in Python is this snippet below. It allows you to evaluate a string and execute it as a Python code.
request_body = '2 ** 2'
response = eval(request_body)
return response
Imagine the possibilities. When you are using this code, an attacker can just modify the request body to a more sinister one.
request_body = 'run_sql("drop database")'
response = eval(request_body)
return response
Much of the programming world does not use this code anymore. But vulnerabilities found in old packages (that you may still be using) may leave you exposed to this vulnerability. Here's an example from an outdated version of Astropy.
[4] Malicious Packages
The dawn of open-source software has allowed developers to share code much freely. It has accelerated development since we no longer have to write code from the ground up. We can just compose libraries together to make our application. But that openness also comes at a price.
There are malicious libraries out there that exist to mimic legitimate software. Once added to your project, these libraries open backdoors for hackers to remotely execute code on your server. Like this "python package"
Malicious code don't exclusively come from packages. It can also come from Lambda layers. An inconvenience with Lambda is that when there are libraries with OS-specific dependencies, it is more difficult to upload them to Lambda. You have to compile the library using an OS that is similar to Lambda's OS. An example of this is psycopg2 (an internal library required to make Postgresql work in Python).
The most convenient way to fix this is just to use a Lambda Layer that somebody else already created. Like this Github page of Keith. While he looks generally reputable, nothing is stopping Keith from inserting malicious code to any one of his public Lambda layers. And once you use the code inside the Lambda layer, he may be able to remotely run code in your lambda. A better fix is to build the lambda layer yourself, even if it takes awhile. In Python, Pip added the --platform
command where you can specific the platform when you install your library.
[5] API is too open
The easiest way to hack an API is when it is open to the public.
What we do is we often pair it with Cognito. The user logs in to the frontend, and Cognito issues a set of tokens that the backend will use to ensure that the user is who he says he is. The token expires every hour and needs to be renewed. During each renewal, we can validate if the session is still valid.
But how about APIs that are only used by other APIs? They shouldn't be open to the public in the first place. They should, at the minimum, be secured by an expiring API token that only the authorized system has access to. An even better approach is to determine these APIs and ensure they can only be accessed privately, inside the network.
[6] Privilege Escalation
ECS tasks and Lambda functions rely on IAM Roles to access AWS services. Those who leave this role with an admin privilege can leave their account open to hacking.
If there is a remote code execution vulnerability, hackers can use that to discover the IAM role inside the Lambda / ECS task. Then, they can use this role to create an IAM user with elevated privileges, which they can use to gain access to your AWS accounts.
But more often than not, this vulnerability is an inside job. For example, we have given the developer limited rights to our AWS account. They can only push code to their CodeCommit repository. But the execution role of the Lambda function is set to Administrator Access. The developer can change the code that is pushed to the CI/CD to include instructions to create an IAM user for him with elevated permissions.
Another form of privilege escalation is modifying the CloudFormation code that comes with the serverless application. Malicious developers can directly add instructions to create an elevated user there.
How about you? What are other ways to "hack" into serverless applications?
Let us know in the comments!
Also check out my other blog post on security best practices we learned the hard way.
Photo by Max Bender on Unsplash
Top comments (0)