In cloud computing, it is often the case that the cloud provider provides the infrastructure necessary to run the application. The cloud provider provides the compute and manages the resources for us. It also uses the power of cloud computing i.e., auto scalability, which means that the serverless application can be scaled according to the needs of the customer traffic. All this is done so that the developers can focus on writing code and leave the worry about managing servers to the cloud provider.
Serverless applications, also called Function-as-a-service (FaaS), is an offering which is provided by all modern cloud services providers. In this service, developers write code and the infrastructure behind the scenes is managed by the provider. Developers can write multiple functions to implement business logic and then all these functions can be easily integrated to talk to each other. This is called serverless architecture.
Below are some of the offerings from the most popular enterprise cloud providers:
We must be aware of two main concepts related to serverless applications:
Functions are stateless – The state of the serverless applications is created when the execution starts and destroyed when the function has been executed successfully. There is no state information being stored automatically about these functions. In case the users need to store the state information then a separate storage system needs to be used e.g., Database.
Functions are event driven – you need an event to occur before a function is executed. An event can be anything like a REST API request, a message added to a queue, etc. The response from the event, also known as a trigger, can be used to fire the execution of a serverless application.
In this article we will look at what AWS Lambda is and discuss various aspects of security of Lambda functions.
AWS Lambda is a serverless compute service provided by Amazon. It is priced based on the duration of the execution of the function and the number of times it is being executed. Customers are charged only for the time during which the code is being run. AWS Lambda also provides support for multiple languages starting from C#, JavaScript, Python, etc. You can author the code in any text or code editor and then upload a zip folder of your code to the IDE in AWS Management Console.
Below are a few events which can be used to trigger a lambda function:
The security of an application is one of its most important non-functional requirements. As serverless architectures are getting more attention from the developer community, they are also catching the eye of hackers. And when it comes to serverless, AWS Lambda deployments are the most common ones we need to look at.
The distributed nature of the serverless application architecture gives a malicious attacker more room for exploitation. The greatest asset of serverless applications (scalability) is the most dangerous foe as well. It gives attackers significant entry points to the application.
Since serverless applications and technologies are trending they are naturally a target for the attackers. To account for this, the OWASP foundation had published an interpretation of the OWASP Top-10 list of Web application security risks the OWASP Serverless Top 10.
Let’s take a look at what various security implications occur in the real world using a deliberately vulnerable application – ServerlessGoat.
It is a common misconception that serverless apps are secure by default because:
There is no managed server
Serverless applications are HTTPS by default
The serverless provider takes care of the security
Just because the application does not use a managed server it does not mean that it is secure. Since there are no managed servers, it minimizes the vulnerability management/ patching part, but the risks are still applicable due to bad programming practices and cloud platform layer misconfigurations.
The folks at OWASP have also released ServerlessGoat which is an intentionally vulnerable serverless application to demonstrate some vulnerabilities that can commonly affect AWS Lambda. The OWASP ServerlessGoat application is packaged as an AWS SAM application that is available for deployment through the AWS Serverless Application Repository.
The installation of ServerlessGoat is quite simple. It only requires a single-click to get deployed in your AWS account, which makes getting up and running a smooth experience. Deploy the below function using the Lambda repository.
Let us understand Lambda attack and defense with some practical examples of attack scenarios using the ServerlessGoat. We will look at some of the vulnerabilities in detail and discuss how to defend them.
Note: All the below attacks are performed in a test non-production AWS account. Do not set up vulnerable apps/setups in prod AWS accounts.
The first step is to know if the application you are accessing is serverless or not! There are many ways to identify it:
3. You can also check for any exceptions that the application throws. Below you can see if we manipulate the URL of the application by removing the parameter “document_url”, it throws a default exception through which we can identify the location of the lambda function at the server side.
The above screenshots throw default exceptions and give us details about serverless / lambda service at server-side. The server is Linux, and the lambda function logic is at “/var/task/index.js”. Let’s see If we can inject some OS commands and see if we get a proper response.
2. OS Command Injection
We will blindly probe for OS command injection using a common payload like “id” invoking a command on the Linux OS system. The malicious payload is “http://foobar.com; id #”.
You can see that the id command is successfully validated, and the response is sent back as in the figure shown above. This confirms that the Lambda function is vulnerable to OS command injection.
Now we will dig for some sensitive data in the environment variables. We will run the same malicious payload but instead of id we will use env command. So, the payload will be “http://foobar.com; env #”.
Since we have got access to the AWS Session Token, Secret Key and Access Key we can further focus on compromising the AWS account.
3. Compromising the Victim AWS Account
Now, export the AWS Session Token, Secret Key and Access Key and we can now get the function’s temporary execution role using AWS Command Line Interface (CLI).
export AWS_SECRET_ACCESS_KEY = ""export AWS_ACCESS_KEY_ID = ""export AWS_SESSION_TOKEN = ""
Verify that you have got access to the Lambda function’s temporary execution role by running the command “aws sts get-caller-identity”. You should have an output as shown below.
It’s clear that we are now running under the assumed role of the function. Now we will dig deeper using the OS command injection and try to access the source code of the Lambda function. We will run the same malicious payload but instead of env we will use cat /var/task/index.js command. So, the payload will be “http://foobar.com; cat /var/task/index.js #”.
Below are the thing which we learnt from the source code review of the Lambda function:
4. Exploiting Over-Privileged IAM Roles
We can confirm from the source code review of the Lambda function that the developer is inserting the client’s IP address and the document URL value into the DynamoDB table, by using the put() method of AWS.DynamoDB.DocumentClient. In a secure system, the permissions granted to the function should be least privileged and minimal, for example, only dynamodb:PutItem.
However, when the developer chose the CRUD DynamoDB policy provided by AWS Serverless Application Model (SAM), they granted the function with the following permissions:
These permissions allow an attacker to exploit the OS command injection weakness to exfiltrate data from the DynamoDB table, by abusing the dynamodb:Scan permission. Use the following payload in the URL field, and see what happens (URL encode the below payload):
https://; node -e 'const AWS = require("aws-sdk"); (async () => {console.log(await new AWS.DynamoDB.DocumentClient().scan({TableName: process.env.TABLE_NAME}).promise());})();'
As you can see from the output below, we accessed the entire contents of the table
Below are some security best practices which can be implemented to secure the serverless apps.
When designing a serverless application architecture, implementing and enabling security best practices is most important for a developer. AWS has a list of security best practices that is recommended for Lambda function security integration.
These are the security best practices that should be implemented on serverless applications
Identity and Access Management (IAM) tole is an AWS identity that can be used to allocate permission policies about what each identity can do. All lambda functions need a single relationship with an IAM role. This ensures that even multiple functions with the same policy are triggered at the same time, all functions will be granted at the same time.
DB credentials, encryption keys and other keys are the best kept secrets in a lambda function. Some options to manage these secrets in the application are:
1. Encryption helpers
2. Use AWS Systems Manager parameter store
API gateway allows the developer ownership over authentication and authorization and is a unique form of event source for lambda function. However, the developers are responsible for ensuring security best practices of the enabling APIs
In case a Lambda function requires access to a VPC resource, the developer needs to keep in mind to enable security best practices through network ACLs (Access Control List), function-specific subnet, security groups, and routing tables that direct the Lambda functions to reach intended destinations.
Decreasing the attack surface by removing the direct access to APIs of any Lambda functions. The lambda APIs must be treated with extreme care and caution and any code changes must be done through automation.
You can use AWS WAF to protect AWS Lambda functions from common web exploits, such as SQL injection and cross-site scripting (XSS) attacks. These could affect availability and performance, compromise security, or consume excessive resources. Although, be aware of certain configurations that could dilute the security that WAF provides significantly.
Adjusting lambda function throttling can be done by increasing your account’s limit to a very high number of concurrent executions. It can also be done by reserving some executions per function, you can reserve a certain amount of your account’s total concurrency limit for a specific function.
This will allow your reserved lambda executions to be untouched by other functions and will be only used by that particular function, preventing throttling of requests due to exceeding your account’s limit.
Monitor the Lambda function dependencies using 3rd party / opensource tools such as Snyk, Black Duck, OWASP Dependency Tracker to mitigate the dependency poisoning attacks on the Lambda functions. If the dependencies go unchecked there are high chances of malicious codes being added to the dependency which in turn is consumed by the Lambda functions making it prone to publicly known vulnerabilities.
As we seen from the demo, all the attacks applicable to a traditional web application are also applicable to the serverless apps as well. Hence it is important to follow security best practices while developing a serverless application and to make sure that the app is regularly reviewed and tested by security teams.