close button
Essential Serverless Security Best Practices for Developers!
profile picture Editorial Team
12 min read Jun 9, 2025

Essential Serverless Security Best Practices for Developers!

Serverless Security Best Practices

We have Akshatha and Divya exploring key security challenges in modern application development in an AntStackTV episode. Here, they cover everything from securing password recovery flows to managing dependency vulnerabilities. Their discussion highlights critical topics like authentication vs. authorization, automation in security, and common threats like denial-of-service attacks.

With real-world examples and best practices, they break down how serverless environments handle security risks and why proactive strategies are essential. Whether you’re a developer refining your security approach or an engineer navigating cloud security challenges, this conversation offers practical insights into building resilient applications.

Setting Up a Secure and Scalable Project

Divya: Recently, I was creating an environment for my new project and exploring all the best practices for setting it up. As we know, security is a critical aspect of any serverless project. From your experience, how do you ensure that security is embedded from the very beginning?

Akshatha: The foundations of the project are the most crucial. Once you have the foundation set up correctly, you can grow the application as much as you want. Extending features, adding new features, or blocking out some features will be even easier when you have the foundation set.

So the most important pillars when setting up a project are infrastructure, design patterns, and architecture.

  • Infrastructure Setup: Since we are a serverless company, we need to focus on infrastructure. Even though we are developers, we set up the infrastructure ourselves. Infrastructure as Code (IaC) is one of the most crucial aspects. Picking the right tool and setting up the rules is essential, that is one of the pillars.
  • Design Patterns: It allow for easy code reusability and maintainability of functions. This ensures that the code remains modular and scalable.
  • Application Architecture: Analyzing the access patterns that will be needed and then choosing the appropriate database and services for different features ensures that the application is future-proof.

Security Best Practices

Divya: Regarding security, what are the best things that you find?

We use Sonar Cloud, as it is very good at analyzing vulnerabilities in the code and providing the best suggestions. The tool gives valuable insights, and you can integrate it with SonarQube for any static application testing, security test analysis, and more.

What’s your take on that?

Akshatha: Security is one of the most crucial pillars of the foundation I was talking about, and that’s exactly what I was coming to. SonarCloud is a tool that plays a vital role in our stack. We always ensure that we connect SonarCloud to our code repositories, as it helps maintain code quality, ensures our test coverage is up to the mark, and checks for any code vulnerabilities.

When developers write code, they may sometimes forget to validate or properly sanitize inputs. SonarCloud recognizes these code patterns, identifies potential issues, and flags critical vulnerabilities as warnings, making developers aware of them.

Input validation and sanitization are essential, especially in the backend, where we directly connect to databases and access data. Since serverless patterns ensure that Lambda functions are stateless, unless you’re using step functions, most Lambda functions involve some form of database call. If input validation and sanitization are inadequate, malicious attackers could send crafted inputs that close quotes and execute arbitrary SQL statements against the database.

Preventing SQL Injection Attacks

Divya: Input validation is a huge part of security. What other checks do you prefer?

Akshatha: The attack I was referring to, where an attacker adds a delimiter and injects an SQL statement, is called SQL injection. They can execute this either through code manipulation or command mirroring.

Checking input patterns using regular expressions and ensuring that user input doesn’t match well-known attack patterns is crucial for preventing such vulnerabilities. Proper input validation and sanitization are key to mitigating these risks.

Akshatha: In a recent project I worked on, we used the Amplify CLI to set up most of our data models. One particularly useful directive was @searchable, which automatically created an OpenSearch instance and generated all the necessary calls to interact with it, fetching the required data. This was especially helpful when implementing free-flow or document searches.

However, one of the client’s key requirements was the ability to search with spaces and special characters, including the ampersand (&). OpenSearch, by default, applies input validation to prevent injection attacks, which meant it would strip out special characters like & before processing the search query. While this security measure ensured safer input handling, it also altered the search behavior, preventing exact matches for queries containing special characters.

Although this approach did not always return results exactly as the client expected, it was enforcing a crucial security best practice, validating and sanitizing input automatically without requiring explicit configuration in our code.

Custom Error Messages for Better Security

Divya: When writing the code, we ensure that the error messages we display are custom-generated. We don’t disclose any information about what resources we are using or what permission levels we are granting; instead, we provide a custom message, which is a very good practice.

Short authentication is a major drawback when dealing with security. Cognito and similar services provide robust security features by default.

How do you feel about authentication and authorization, and what level do we need to give?

Akshatha: I learned something interesting about authentication in the last year of my college is that the error messages you provide can be easily exploited.

For example, on a login page with email and password fields, an attacker might know the email but not the password. If the platform specifies which field is incorrect - “Your email is invalid” or “Your password is incorrect”, the attacker can use this information to brute-force their way into the account. Instead, a generic message like “Either your email or password is incorrect” makes it harder for attackers to pinpoint their approach.

Divya: Similarly, when users click “Forgot Password,” we don’t say, “We will send the reset link to [specific email].” Instead, we say, “We will send a password reset email to the email registered with our platform.”

Akshatha: Exactly! In these cases, we avoid displaying the actual email ID. This makes it harder for attackers to identify valid email addresses, adding another layer of security.

Managing Package Updates and Dependency Security

Akshatha: Coming back to the tools we were using, another important aspect that we cover in our environment setup is ensuring that we don’t introduce vulnerabilities when package updates occur. A useful tool in this scenario is Snyk. This tool detects vulnerabilities in packages when they are updated. Sometimes, updates happen automatically, and when there’s a major update, it might not be backward-compatible, which can break your application.

Divya: Something similar happened with our project. We were using MjML packages, and there was a major upgrade. This particular application used a new MjML version with a dependency package called Cheerio. At one point, Cheerio had an upgrade that introduced new dependency packages into our tech stack. However, some of these were incompatible with our application, which broke a couple of our functions. We had to go through many repository logs, information, and package monitoring sites to find out that this upgrade was the cause of the breakage.

Akshatha: Snyk could have been useful in that situation. It would have pointed out the exact package causing the issue, saving us time and effort.

Authentication vs. Authorization

Akshatha: Since we spoke about authentication earlier, there is a small but important difference between authentication and authorization that I would like to highlight here.

Authentication verifies that a user is who they claims to be. Think of it like an airport security check: you show your passport, and the officer matches your face to the photo to confirm your identity. In software terms, this is the process of entering an email and password to log in and the system knows that you are really who you are.

Authorization, on the other hand, determines what resources a user can access after authentication. This is where the principle of least privilege comes in. Can you elaborate on that?

Divya: Sure. When adding a resource to an application, we can limit user privileges. We define different user lists with specific access levels, ensuring that users only receive the necessary permissions, nothing more, nothing less. This principle of least privilege ensures that we don’t accidentally expose critical resources.

Akshatha: That makes sense. Why would you give a user unnecessary access and make important resources vulnerable.

Divya: Exactly. IAM roles and Cognito groups are very effective in managing permissions. They allow us to assign different permission levels based on roles while maintaining security. There’s also the concept of time-sensitive privileges.

Akshatha: That’s where Just-in-Time privilege management comes in. This approach grants users access to resources only for a limited time. Once the time limit expires, access is revoked. This can apply to roles, users, applications, or even cloud resources. Implementing such policies makes environments more secure.

Testing and Automation

Divya: When you develop, testing has a very important role. The kind of unit testing we do is mandatory, whenever you create a function, you immediately write the test cases for that function and test it out. I believe that it’s good to automate this testing as a team-wide practice.

Whenever you build an application and set up GitHub Actions, it’s good to have those tests run automatically, including stress tests as well. That is also a good practice. I believe when creating the environment itself, we can do that as well.

I’m a huge fan of SonarCloud in that sense because it gives you details like how much code coverage there is and other such insights while you’re writing the test cases. That is a good thing. And with all those tools that we use for testing, is there any other tool that you prefer to use for testing or for automating the testing?

Akshatha: For automation, we prefer to include it within the CI/CD pipeline used by the application. In many cases, that’s GitHub CI/CD; in some cases, it’s AWS CodeCommit. Based on what we pick, we add the automation there.

Another important aspect, which relates to testing, is that some test suites require access to AWS resources or other infrastructure. While mocking can work in many scenarios, when you have integration testing in place, certain resources are actually used in your test cases.

In such cases, it’s crucial to ensure that secrets are managed correctly and in line with best practices. If a developer accidentally commits secrets to a code repository and that repository becomes public at any point, anyone can go back through the commit history and retrieve those secrets. That makes your resources vulnerable and could lead to misuse or overuse.

Always store secrets in a secure service, whether it’s AWS Secrets Manager, GitHub Secrets, or Systems Manager Parameter Store. It’s important to choose the right service based on the level of security you need. But above all, it’s critical that these credentials are stored properly.

Common Security Threats and Mitigation

Akshatha: Speaking of security, what are some common attacks that serverless applications are prone to?

Divya: SQL injection is one of the most well-known attacks, but serverless architectures tend to have robust data management and API security, making SQL injections less common. We also use parameterized queries to prevent the direct execution of user input as code. Another common attack is cross-site scripting (XSS), but output encoding and encryption help mitigate that risk. Denial-of-service (DoS) attacks, however, are still a concern.

Akshatha: Yes, DoS attacks happen when an attacker floods an API with too many requests, preventing genuine users from accessing it.

Divya: We mitigate this by using firewalls and rate limiting. If a particular IP makes too many requests in a short window, we throttle those requests to protect system resources and prevent unnecessary costs.

Akshatha: Throttling ensures that if a particular IP is making a large number of requests in a short period, it gets blocked from making further requests. This helps save service resources while ensuring that genuine users can access the platform without disruption. Throttling is crucial in serverless environments because of their vulnerability to denial-of-service attacks. Another common attack is buffer overflow.

Divya: That’s not a concern for us because we use memory-safe languages like JavaScript and Python, which have automatic garbage collection. This means unnecessary files or memory references aren’t stored persistently, reducing the risk of buffer overflow vulnerabilities.

Akshatha: C and C++ are more prone to these issues because they are not garbage-collected languages. Developers have to manually revoke void pointers and ensure they don’t point to unintended memory locations. If mishandled, this could lead to information leaks from memory. However, in our serverless environment, where we work primarily with Python and JavaScript, this isn’t an issue because both languages handle memory management automatically.

Vulnerability Detection Tools

Akshatha: Now, what do you think about vulnerability detection tools for applications?

Divya: There are many tools available today. One that comes to mind is Amazon Security Hub. It collects logs from servers and network resources, organizes them by priority, and provides best-practice recommendations to prevent security breaches. Another valuable tool is the Elastic Stack, which monitors network traffic and logs in real-time. It integrates machine learning to detect anomalies, pinpoint vulnerable servers, and prevent malicious injections.

I also believe that following OWASP principles from the start is a good approach. OWASP provides structured guidelines on best security practices, from writing error messages to handling authentication and authorization securely.

Akshatha: Absolutely. OWASP is the best resource for understanding security vulnerabilities and best practices. They provide documentation on everything from secure API development to authorization strategies, helping developers stay up to date with the latest security standards.

Catch up on the episode on AntStack TV and subscribe to hear from serverless experts as they share practical insights and strategies making technology work for you.

Application Modernization Icon

Explore limitless possibilities with AntStack's frontend development capabilities. Empowering your business to achieve your most audacious goals. Build better.

Talk to us

Author(s)

Tags

Your Digital Journey deserves a great story.

Build one with us.

Recommended Blogs

Cookies Icon

These cookies are used to collect information about how you interact with this website and allow us to remember you. We use this information to improve and customize your browsing experience, as well as for analytics.

If you decline, your information won’t be tracked when you visit this website. A single cookie will be used in your browser to remember your preference.