DEV Community

Rahman Badru
Rahman Badru

Posted on

Enhance Your Web Protection: AWS WAF Essentials

What is the AWS WAF?

The AWS WAF which stands for Web Application Firewall is a tool that lets you monitor requests to your web application resources. It protects some of the following AWS Resources like:

  • Amazon Cloudfront Distribution
  • Application Load Balancer
  • Amazon API Gateway REST API and a couple of other resources.

What does the AWS WAF do?

It basically lets you control access to your content, Based on whatever conditions you specify e.g the IP addresses the requests come from, the path being requested or the location the requests originate from , the service associated with whichever resource is being protected either gives the right response, or a forbidden permission response ( also known as the 403 error) or a custom response configured by the user.

How does the AWS WAF work?

The WAF works to control how your protected resources respond to web requests and it does that using a Web ACL (Access Control List) and associating it with the resources to be secured. The resources then forward any incoming requests to the ACL for inspection.

With the web access control list,you define rules for traffic patterns which you look for in those requests,and then set the action to be taken on requests that match the patterns, which can include:

  • Allow the requests to go to the protected resource for processing and response.

  • Block the requests.

  • Run CAPTCHA or challenge checks against requests to verify human users

Components of the WAF

These are some of the components that make up the AWS WAF

  1. Web ACL: You use this to protect your AWS resources via rules, The rules help define the criteria for the requests coming in and also the action to take on requests that match the rules, You can set default actions on matched requests as listed above. As an example, you can set a rule to block all requests coming from a specific IP address.

  2. Rules: These are the building blocks of the Web ACL and they determine what actions are to be taken on requests.

  3. Rule Groups: A rule group is a reusable set of rules that you can add to a web ACL.

Configuring the AWS WAF (Walkthrough)

To show the capabilities of the AWS Web Application Firewall, we will create an EC2 Instance running Wordpress, place it behind an Application Load Balancer and associate a WAF Web ACL to it.

We will then explore rules we can create , as well as set up logging for the WAF.

Step 1 - Creating the EC2 Instance.

First we create the EC2 Instance , using a wordpress image gotten from this link:

Copy the image id for the region you want to deploy the instance in.

Image description

Login to the AWS EC2 Console: EC2 Console

Click on launch instance.

Image description

Give the instance , the name wordpress .

Under Application and OS Images, Paste the image ID you copied and search for it under Community Images.

Select the Image

Image description

Image description

Leave the instance type as default (t2.micro) which is free tier

Set the key pair login to "Proceed without a keypair" as we don't need access to the instance.

Under Network settings, click edit

Image description

Make sure the default VPC is selected and ensure auto assign public IP is enabled.

Create a new security group named wordpress-waf and change the security group rule 1 to HTTP.

Image description

Leave all other settings as default and launch the instance.

Once the instance has been created, copy the public ip and navigate to it in your browser.

Image description

You should see the wordpress default page.

Image description

Step 2 - Creating a target group.

Go back to the EC2 Console: EC2 Console

Go to target groups and click on create target group.

Image description

Choose the target type as instances.

Image description

Set the target group name to be wordpress

Leave everything else as default and click Next.

Select the instance created previously and select include as pending below.

Image description

Click on create target group.

Step 3 - Creating an Application Load Balancer.

On the EC2 Console Page , click on load balancers and then create load balancer.

Image description

Select the Application Load Balancer.

Image description

Set the Load Balancer name to wordpress-lb

Make sure the VPC is default and select all subnets under Network mapping.

Image description

Under Security Groups, select the wordpress-waf group we created

Image description

Under Listeners and Routing , change the action for HTTP to forward to the wordpress target group we created earlier.

Image description

Leave all other settings and create the load Balancer.

Once the ALB ( Application Load Balancer ) is created , Paste the DNS Name in the Browser, you should see the same wordpress default page as earlier.

Image description

Image description

Step 4 - Creating an s3 Bucket for WAF Logs.

Head to the S3 Console: S3 Console

Go to Buckets and click create bucket.

S3 buckets for aws waf logs must begin with aws-waf-logs- , so name your bucket with that prefix.

Make sure the bucket is in the same region as your EC2 Instance.

Leave all other settings as default and create the bucket.

Image description

Step 5 - Setting up the WAF.

Go over to the WAF Console, which can be found here:

Ensure that the region is the same as the region your instance is in, in my case, its the us-east-1 region.

First, we would create an IP Set, which is basically a group of IP's ( which is used commonly for IP addresses you want to allow). IP Sets can contain up to 10,000 CIDR ranges, which makes allowing or blocking large numbers of networks very easy.

Check your IP address using this link: and copy your IP Address.

Go to IP Sets and create IP Set.

Image description

Set the IP Set name to home-ip

In the IP Addresses box, add the IP you copied with the /32. e.g

Image description

Create the IP Set.

Go to Regex Pattern Sets and click on create regex pattern set.

Image description

Set the regex pattern name to no-wp-files

In the Regular expressions box, enter:

Enter fullscreen mode Exit fullscreen mode

Click on create regex pattern set.

Image description

Go to Web ACL and click on create Web ACL

Image description

Under Resource Type, click Regional Resources.

Set the Name to wordpress-acl.

Image description

Under Associated AWS Resources, click Add AWS Resources.

Image description

Under AWS Resources, click on Application Load Balancer and select the ALB we created earlier.

Image description

Click on next.

Under Rules, click on Add Rules, and then Add Managed rule groups.

Image description

Expand AWS Managed Rule Groups and you will see a list of WAF rule groups that are supplied and maintained by AWS.

Under the Free Rule Groups, Select the following.

  • Core rule set
  • PHP application
  • SQL database
  • WordPress application

Each rule group has a description showing what kind of attacks the rule group helps protect against.

Given that our infrastructure is centered around a WordPress application, it's essential to prioritize the WordPress rules for enhanced protection. Additionally, since WordPress is PHP-based, integrating PHP application rules is crucial. As our WordPress database relies on MySQL, implementing the SQL database rule set becomes imperative to safeguard against potential SQL Injection attacks, among other threats.

The “Core rule set” contains the most rules, and protects against common attack methods provided by the open source OWASP organisation

Image description

Click on Add rules.

Note: each rule group has a “capacity” value. Each Web ACL has a maximum capacity of 1500 “WebACL Capacity Units” (WCUs), and each rule we add uses up some of those units. E.g The SQL rule has a capacity value of 200.

Under the Default web ACL action for requests that don't match any rules , set it to Allow, this is because we only want to block traffic matching any of our rules.

Click on Next.

You can also set the rule priority for the rules selected earlier. Web ACL rules are executed top to bottom, so the first rule is executed first and so on.

Image description

Click Next and ensure that Request sampling options is set to enabled.

Create your Web ACL

Once the WAF has been created, click on it and under Logging and metrics, click Enable

Image description

Then click on s3 bucket as logging destination and select the bucket we created earlier.

Then save.

Image description

Step 6 - Testing the WAF.

Open the ALB URL that we visited earlier.

We should be able to view the wordpress page, and even the blog and admin page (/sample-page/ and /wp-admin).

If we try a simple SQL Injection Attack like : /wp-login.php?user=1+ORDER+BY+10 , the WAF should stop us with a code 403 ( permission denied).

Image description

Once verified that the WAF rules are working as expected.

Go back to the WAF Console, click on your WAF and navigate to the Sampled requests.

Image description

If you search for your IP Address, you should see the requests you made, the actions applied on those requests (ALLOW/BLOCK) and the rule that cause any block action.

Image description

Step 7 - Adding Custom Rules to your WAF Web ACL.

We don’t want our WordPress login page or XML-RPC page being accessed by anyone, so we’re going to use our regex pattern we created earlier to block any requests to /wp-login.php or /xmlrpc.php

Go to your WAF console:

Click on your wordpress web acl.

Navigate to rules. Then click on Add rules, and add my own rule and rule groups

Image description

Leave the rule type as Rule Builder and name it no-wp-files.

Leave the type as a regular based rule.

Under the block If a request matches the statement, set the inspection option to URI Path

Set Match Type to “Matches pattern from regex pattern set”

Set Regex pattern set to the pattern set we created earlier (no-wp-files).

Set Text transformation to “Lowercase” ,this changes everything in our inspection option which is the URI path to lowercase. e.g /wp-login.php and /WP-LOGIN.PHP will be seen by the WAF as /wp-login.php

Image description

Under Action, Select Block

Image description

On the next page, we need to move our new rule to the top of the priority list. Remember that rules in Web ACL are executed in order of top to bottom.

Select your new rule, and keep clicking Move up until it’s at the top of the list.

Image description

Then save

Now if we try accessing either the /wp-login.php,/wp-admin or /xmlrpc.php. We will get a 403 forbidden message.

Image description

If we check the sampled requests of the AWS WAF console, we would see our IP and the path requested, with the action shown as BLOCK.

Image description

We can also add many other custom rules such as:

  • Allowing our home ip access to the application, since it is a trusted ip
  • Allowing requests coming from a particular country, while blocking all other requests.

Step 8 - Viewing our WAF Logs.

We can view our WAF Logs by going to the bucket we created in the S3 Console: S3 Console.

Go to buckets and click on our waf logs bucket.

The directory structure will be:


Image description

You can download the logs (which is in the .log format) and view it using the json pretty print website:, as the json file might be difficult to read.

An example of a log can be this:

  "timestamp": 1713169621018,
  "formatVersion": 1,
  "webaclId": "arn:aws:wafv2:us-east-1:567635759120:regional/webacl/wordpress-acl/24ce438c-a4b9-467f-8b4c-ba5ab8d56db3",
  "terminatingRuleId": "no-wp-files",
  "terminatingRuleType": "REGULAR",
  "action": "BLOCK",
  "terminatingRuleMatchDetails": [
      "conditionType": "REGEX",
      "location": "URI",
      "matchedData": null,
      "matchedFieldName": ""
  "httpSourceName": "ALB",
  "httpSourceId": "567635759120-app/wordpress-lb/3630369d4fc6a356",
  "ruleGroupList": [
      "ruleGroupId": "AWS#AWSManagedRulesPHPRuleSet",
      "terminatingRule": null,
      "nonTerminatingMatchingRules": [],
      "excludedRules": null,
      "customerConfig": null
  "rateBasedRuleList": [],
  "nonTerminatingMatchingRules": [],
  "requestHeadersInserted": null,
  "responseCodeSent": null,
  "httpRequest": {
    "clientIp": "",
    "country": "NG",
    "headers": [
        "name": "Host",
        "value": ""
        "name": "Connection",
        "value": "keep-alive"
        "name": "Upgrade-Insecure-Requests",
        "value": "1"
        "name": "User-Agent",
        "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/ Safari/537.36"
        "name": "Accept",
        "value": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"
        "name": "Accept-Encoding",
        "value": "gzip, deflate"
        "name": "Accept-Language",
        "value": "en-GB,en-US;q=0.9,en;q=0.8"
    "uri": "/xmlrpc.php",
    "args": "",
    "httpVersion": "HTTP/1.1",
    "httpMethod": "GET",
    "requestId": "1-661ce4d5-403eac0b43ee412a6810f599"
Enter fullscreen mode Exit fullscreen mode

Here in this log file,you see the ACTION set to block and the terminating rule ID is the no-wp-files custom rule we created earlier.

You can also see all of our request headers are there, as well as the URI, query strings, etc. This can be removed if you prefer.

Step 9- Clean Up.

Ensure all the resources created during this walkthrough are deleted. These include :

  • Web ACL
  • IP Sets
  • Regex Pattern Sets
  • S3 Bucket
  • EC2 Instance
  • Target Groups
  • Load Balancer
  • Security Groups

I trust that this article has effectively demonstrated the capabilities of AWS WAF and provided you with a deeper understanding of its functionality and implementation.


AWS WAF Documentation
Andrew Cantrill's WAF Demo Guide

Top comments (0)