AWS CloudFront & WAF: How to Mitigate Common Attacks on Serverless Applications
The last installment in this series on serverless best practices on AWS covered Transport Layer Security with Certificate Manager and some strategies for implementing custom authorizers. In this entry, we’ll wrap up endpoint security with a look at how to use AWS Web Application Firewall (WAF) and CloudFront to mitigate common attacks like SQL Injection, Cross-Site Scripting, and Distributed Denial of Service (DDoS).
What Are AWS CloudFront and WAF?
AWS CloudFront and WAF are managed services provided by AWS with no infrastructure for you to manage, so they’re an obvious extension of your serverless stack. However, everything here can also be used for traditional, server-bound applications.
These AWS services provide simple ways to ensure that your application is protected from common vulnerabilities, which means your developers can spend less time worrying about them and more time building valuable product features.
Recommended CloudFront and WAF Architecture
Until fairly recently, WAF did not support direct integration with API Gateway, so the usual pattern was to integrate WAF with a CloudFront distribution, and put that in front of API Gateway.
However, since AWS announced support for direct WAF / API Gateway integration, this is no longer strictly necessary.
Depending on your use case, it may still be beneficial to use the old pattern, as CloudFront also provides useful features to help secure your application.
Using AWS WAF to Mitigate Attacks
AWS Web Application Firewall is a Layer 7 firewall that inspects the contents of your HTTP(S) requests and filters them based on rules you specify. Traditional network firewalls can only filter based on network properties like IP address and port.
Because WAF can inspect the payload of the request, it’s a powerful tool for detecting and preventing common attacks like SQL Injection and Cross-Site Scripting (XSS), as well as rate limiting, geographic matching, or even filtering requests with regular expressions.
WAF can filter requests forwarded to a variety of AWS services, including CloudFront distributions, API Gateway REST APIs, Application Load Balancers, or AWS AppSync. WAF inspects all requests and will only allow the traffic that meets your criteria.
Traditional network-based firewalls let you define Access Control Lists (ACLs), which filter traffic based on IP address and other networking details. WAF defines Web ACLs, which can filter traffic in more complicated ways.
WAF comes with predefined rules to filter out requests that contain SQL Injection attacks, Cross-Site Scripting attacks. It also allows you to easily define rules based on simple string matches, payload size, and more.
Multiple rules can be grouped together with simple logic (AND, OR, etc.) to create Rule Statements for even more fine-grained control.
WAF and the OWASP Top 10
The OWASP Foundation maintains a list called the OWASP Top 10, which “represents a broad consensus about the most critical security risks to web applications.” AWS has published a whitepaper with step-by-step instructions for using WAF to mitigate the OWASP Top 10. You can find it here.
Even better, AWS has also published a ready-to-use CloudFormation template that implements the guidance in that witepaper, so you can protect your application from those vulnerabilities with just a few clicks. A link to that template can be found in the AWS blog post here.
Using AWS CloudFront to Mitigate Attacks
Using CloudFront to serve static content like media files and images is a common strategy to improve load times and reduce bandwidth costs. CloudFront is a fast content delivery network (CDN) that caches your content at edge locations closer to your customers, so response times for cached requests are faster and never touch your origins.
CloudFront can also be used in combination with WAF, Route 53 and AWS Shield to help protect applications against DDoS attacks. A full explanation of the setup is beyond the scope of this post, but AWS has a detailed blog entry on how to implement that protection with step-by-step instructions that you can find here.
One often-overlooked feature of CloudFront is field-level encryption. This feature allows you to automatically encrypt sensitive information from HTTPS web forms like credit card numbers and PII when the request hits CloudFront, before it hits your application code. You provide CloudFront with an encryption key and tell it what fields to encrypt.
This feature ensures that your application never handles sensitive data in plaintext, and can make it easier to meet security compliance requirements like PCI DSS. You can store the encrypted data, and ensure that only authorized users with the appropriate encryption keys can access it.
An example flow looks like:
- A user submits an HTML form with a credit card number, which generates a POST to CloudFront
- Field-Level Encryption intercepts the POST and encrypts the card number with an RSA public key
- The card number in the HTML form is replaced with encrypted data
- The application flow continues as normal, except that the application code never handles card numbers in the clear
- The card number is stored in an encrypted state
- If an auditor or other authorized user requires access to the decrypted card number, they can access it with the appropriate keys
Security Best Practices for AWS CloudFront and WAF
CloudFront lets you specify what protocols can be used when end-users make secure connections, including support for forcing TLSv1.1 and TLSv1.2.
Make sure that your CloudFront distribution doesn’t allow users to communicate with SSLv3, which is less secure than TLS. AWS provides detailed guidance on using HTTPS with CloudFront here.
Make sure that traffic between the CloudFront CDN and your origin is encrypted. CloudFront will technically allow you to leave this connection insecure unless configured otherwise. Instructions on how to make sure your origin connections are secure can be found here.
Use Origin Access Identity for S3 Content
Probably the most common use case for CloudFront is to cache static content being served out of S3 buckets. It’s always best practice to keep S3 buckets private, but a common mistake is to enable public access to the S3 bucket so CloudFront can use it as an origin.
CloudFront has a feature called Origin Access Identity, which essentially allows you to create a virtual IAM user for your CloudFront distribution. With this feature, you can keep your S3 bucket private and only allow access to the virtual user you’ve created.
Learn More About AWS Security Practices for Serverless Endpoints
Along with the previous post in this series, this wraps up our look at best security practices for serverless endpoints. Hopefully you’ve found a few useful tips that can help improve your security immediately. In the next entry, we’ll look at how to tie a lot of these practices together with automation, and deploy your serverless application securely and repeatably.
If you’re looking for more support in your cloud security efforts, get in touch with our team. For years, we’ve been solving complex security issues with simple, frictionless solutions. We’d love to help you.