AWS WAF Classic Global Rule Has at Least One Condition
Overview
This check verifies that your AWS WAF Classic Global rules contain at least one condition. WAF Classic rules need conditions to define which web requests to inspect and filter. A rule without conditions serves no purpose and leaves your web applications unprotected.
Important: AWS WAF Classic is the legacy version of WAF. AWS recommends migrating to AWS WAFv2, which offers improved features and a unified API. This tutorial covers remediation for existing WAF Classic configurations.
Risk
A WAF Classic Global rule without any conditions cannot inspect or filter traffic. This creates several security problems:
- False sense of security: The rule appears to be protecting your application but actually does nothing
- SQL injection and XSS attacks: Malicious requests pass through unchecked
- Data theft: Attackers can exploit application vulnerabilities to steal sensitive data
- Service disruption: Bot attacks and denial-of-service attempts are not blocked
- Compliance gaps: Security audit findings for regulations like PCI DSS and KISA ISMS-P
Severity: Medium
Remediation Steps
Prerequisites
- AWS Console access with permissions to modify WAF Classic settings
- Access to us-east-1 region (WAF Classic Global rules are managed from this region)
- An existing condition to attach (IP set, string match, etc.), or permission to create one
Understanding WAF Classic components
WAF Classic uses a hierarchical structure:
- Web ACL: The top-level container that is associated with CloudFront distributions
- Rules: Define how to handle requests that match certain conditions
- Conditions: The actual matching criteria (IP addresses, strings, SQL injection patterns, etc.)
A rule must have at least one condition to perform any filtering. The condition types available are:
- IP match conditions: Match requests from specific IP addresses or ranges
- String match conditions: Match specific strings in request headers, URI, etc.
- SQL injection match conditions: Detect SQL injection attempts
- Cross-site scripting match conditions: Detect XSS attack patterns
- Size constraint conditions: Match based on request size
- Geo match conditions: Match based on geographic location
- Regex match conditions: Match using regular expressions
AWS Console Method
- Sign in to the AWS Console
- Navigate to WAF & Shield (search for it in the search bar)
- In the left sidebar, click Switch to AWS WAF Classic
- Ensure you are in the Global (CloudFront) region selector
- Click Rules in the left sidebar
- Find and select the rule that has no conditions
- Click Edit rule
- Under Add conditions, select the type of condition you want to add:
- Choose an existing condition from the dropdown, OR
- Click Create to create a new condition of that type
- Configure the condition to match malicious traffic patterns relevant to your application
- Click Update
Tip: If you are unsure which condition to add, start with an IP match condition using a test IP address, then replace it with meaningful threat data later.
AWS CLI (optional)
Step 1: Get a Change Token
WAF Classic requires a change token for any modification:
CHANGE_TOKEN=$(aws waf get-change-token --region us-east-1 --query 'ChangeToken' --output text)
echo "Change token: $CHANGE_TOKEN"
Step 2: List Existing Conditions
Before adding a condition to your rule, identify available conditions:
List IP Sets:
aws waf list-ip-sets --region us-east-1
List Byte Match Sets (string matching):
aws waf list-byte-match-sets --region us-east-1
List SQL Injection Match Sets:
aws waf list-sql-injection-match-sets --region us-east-1
List XSS Match Sets:
aws waf list-xss-match-sets --region us-east-1
Step 3: Create a Condition (if needed)
If you do not have an existing condition, create one. Here is an example creating an IP set:
# Get a new change token
CHANGE_TOKEN=$(aws waf get-change-token --region us-east-1 --query 'ChangeToken' --output text)
# Create an IP set
aws waf create-ip-set \
--name "BlockedIPs" \
--change-token "$CHANGE_TOKEN" \
--region us-east-1
Note the IPSetId from the output for use in the next step.
Step 4: Add the Condition to the Rule
# Get a fresh change token
CHANGE_TOKEN=$(aws waf get-change-token --region us-east-1 --query 'ChangeToken' --output text)
# Update the rule with the condition
aws waf update-rule \
--rule-id <RULE_ID> \
--change-token "$CHANGE_TOKEN" \
--updates '[
{
"Action": "INSERT",
"Predicate": {
"Negated": false,
"Type": "IPMatch",
"DataId": "<IPSET_ID>"
}
}
]' \
--region us-east-1
Replace:
<RULE_ID>with your WAF Classic rule ID<IPSET_ID>with the ID of the condition you want to add
Predicate Types:
| Type | Description |
|---|---|
IPMatch | IP address matching |
ByteMatch | String matching |
SqlInjectionMatch | SQL injection detection |
XssMatch | Cross-site scripting detection |
SizeConstraint | Request size matching |
GeoMatch | Geographic matching |
RegexMatch | Regular expression matching |
Step 5: Verify the Update
aws waf get-rule \
--rule-id <RULE_ID> \
--region us-east-1
Confirm the Predicates array is no longer empty.
CloudFormation (optional)
CloudFormation Template
This template creates a WAF Classic Global rule with an IP match condition:
AWSTemplateFormatVersion: '2010-09-09'
Description: WAF Classic Global rule with IP match condition
Resources:
BlockedIPSet:
Type: AWS::WAF::IPSet
Properties:
Name: BlockedIPSet
IPSetDescriptors:
- Type: IPV4
Value: 192.0.2.0/24
WebRequestRule:
Type: AWS::WAF::Rule
Properties:
Name: BlockMaliciousIPs
MetricName: BlockMaliciousIPsMetric
Predicates:
- DataId: !Ref BlockedIPSet
Negated: false
Type: IPMatch
WebACL:
Type: AWS::WAF::WebACL
Properties:
Name: GlobalWebACL
DefaultAction:
Type: ALLOW
MetricName: GlobalWebACLMetric
Rules:
- Action:
Type: BLOCK
Priority: 1
RuleId: !Ref WebRequestRule
Outputs:
RuleId:
Description: WAF Classic Rule ID
Value: !Ref WebRequestRule
IPSetId:
Description: IP Set ID
Value: !Ref BlockedIPSet
WebACLId:
Description: Web ACL ID
Value: !Ref WebACL
Deploy the stack (must be in us-east-1 for Global scope):
aws cloudformation create-stack \
--stack-name waf-classic-rule-with-conditions \
--template-body file://waf-classic-rule.yaml \
--region us-east-1
Adding a Condition to an Existing Rule
If you have an existing rule in CloudFormation without conditions, add the Predicates property:
ExistingRule:
Type: AWS::WAF::Rule
Properties:
Name: MyExistingRule
MetricName: MyExistingRuleMetric
Predicates:
- DataId: !Ref SomeIPSet
Negated: false
Type: IPMatch
Terraform (optional)
Terraform Configuration
provider "aws" {
region = "us-east-1"
}
# IP Set for blocking malicious IPs
resource "aws_waf_ipset" "blocked_ips" {
name = "blocked-ips"
ip_set_descriptors {
type = "IPV4"
value = "192.0.2.0/24"
}
}
# WAF Classic Rule with IP match condition
resource "aws_waf_rule" "block_malicious_ips" {
name = "BlockMaliciousIPs"
metric_name = "BlockMaliciousIPsMetric"
predicates {
data_id = aws_waf_ipset.blocked_ips.id
negated = false
type = "IPMatch"
}
}
# Web ACL to use the rule
resource "aws_waf_web_acl" "global_acl" {
name = "GlobalWebACL"
metric_name = "GlobalWebACLMetric"
default_action {
type = "ALLOW"
}
rules {
action {
type = "BLOCK"
}
priority = 1
rule_id = aws_waf_rule.block_malicious_ips.id
type = "REGULAR"
}
}
output "rule_id" {
description = "WAF Classic Rule ID"
value = aws_waf_rule.block_malicious_ips.id
}
output "ipset_id" {
description = "IP Set ID"
value = aws_waf_ipset.blocked_ips.id
}
Adding a Condition to an Existing Rule
If you have an existing aws_waf_rule resource without predicates, add the predicates block:
resource "aws_waf_rule" "existing_rule" {
name = "ExistingRule"
metric_name = "ExistingRuleMetric"
# Add this block
predicates {
data_id = aws_waf_ipset.some_ipset.id
negated = false
type = "IPMatch"
}
}
Apply the Configuration
terraform init
terraform plan
terraform apply
Verification
After adding a condition to your rule, verify the configuration:
- Open the WAF & Shield console
- Click Switch to AWS WAF Classic in the left sidebar
- Ensure you are in the Global (CloudFront) region
- Click Rules in the left sidebar
- Select your rule
- Confirm the Conditions section shows at least one condition
CLI verification commands
Check if a rule has conditions:
aws waf get-rule \
--rule-id <RULE_ID> \
--region us-east-1 \
--query 'Rule.Predicates'
Expected output when conditions exist:
[
{
"Negated": false,
"Type": "IPMatch",
"DataId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"
}
]
If the rule has no conditions, the output will be:
[]
Re-run Prowler to confirm the check passes:
prowler aws --check waf_global_rule_with_conditions
Additional Resources
- AWS WAF Classic documentation
- Working with rules in AWS WAF Classic
- Migrating from AWS WAF Classic to AWS WAFv2
- AWS WAF pricing
Notes
-
Migration recommended: AWS WAF Classic is a legacy service. AWS strongly recommends migrating to AWS WAFv2, which provides a unified API for both global (CloudFront) and regional resources, better rule management, and enhanced features. Use the AWS WAF migration guide for assistance.
-
Global scope: WAF Classic Global rules are used with Amazon CloudFront distributions. They must be managed from the
us-east-1region, even though CloudFront is a global service. -
Change tokens: All WAF Classic modification operations require a change token. The token is valid for a limited time and can only be used once. Always get a fresh token before each operation.
-
Empty rules create false confidence: A rule without conditions will be listed in your Web ACL but provides zero protection. This can mislead security reviews into thinking protection is in place.
-
Condition planning: Before adding conditions, plan your filtering strategy. Consider what threats are relevant to your application and create conditions that effectively block malicious traffic without impacting legitimate users.
-
Testing: After adding conditions, monitor your WAF logs and metrics to ensure the rule is functioning as expected and not blocking legitimate traffic.