Home AWS WAF and CloudFront: Enterprise Application Protection Against OWASP Top 10
Post
Cancel

AWS WAF and CloudFront: Enterprise Application Protection Against OWASP Top 10

Introduction

Web application attacks continue to evolve at an unprecedented pace, with automated tools making it easier than ever for attackers to exploit common vulnerabilities. According to recent industry research, 94% of applications have at least one high-severity security flaw, and web application attacks account for over 43% of all data breaches in 2024.

Traditional approaches using nginx and ModSecurity, while effective, require significant infrastructure management, patching, and scaling considerations. AWS Web Application Firewall (WAF) integrated with CloudFront provides a cloud-native solution that addresses these challenges while offering superior performance, automatic scaling, and reduced operational overhead.

This comprehensive guide demonstrates how to implement enterprise-grade application protection using AWS WAF and CloudFront to defend against SQL injection, cross-site scripting (XSS), and the complete OWASP Top 10 vulnerability categories.

Current Landscape Statistics

  • 94% of applications contain at least one high-severity security vulnerability (Veracode, 2024)
  • 43% of data breaches involve web application attacks (Verizon DBIR, 2024)
  • $4.88M average cost of a data breach involving web applications (IBM, 2024)
  • 73% reduction in attack traffic when AWS WAF is properly configured (AWS Security Report, 2024)
  • 99.95% availability SLA provided by CloudFront global edge network

AWS WAF Architecture and Core Components

Understanding AWS WAF v2 Architecture

AWS WAF v2 provides a robust, scalable web application firewall that integrates seamlessly with CloudFront, Application Load Balancer (ALB), and API Gateway. Unlike traditional solutions, AWS WAF operates at the edge through CloudFront’s global network, providing protection before traffic reaches your origin servers.

graph TB
    A[User Request] --> B[CloudFront Edge Location]
    B --> C[AWS WAF Rules Evaluation]
    C --> D{Request Allowed?}
    D -->|Yes| E[Origin Server]
    D -->|No| F[Block/Rate Limit Response]
    C --> G[CloudWatch Logging]
    C --> H[AWS WAF Metrics]

Key AWS WAF Components

Web ACLs (Access Control Lists): Container for rules and rule groups that define the filtering logic Rules: Define conditions for inspecting web requests (IP addresses, HTTP headers, URI strings, SQL code, XSS scripts) Rule Groups: Collections of rules that can be reused across multiple Web ACLs IP Sets: Collections of IP addresses and IP address ranges for efficient IP-based filtering Regex Pattern Sets: Regular expression patterns for advanced string matching

OWASP Top 10 Protection Implementation

Core Rule Groups Configuration

AWS provides managed rule groups that specifically target OWASP Top 10 vulnerabilities. Here’s a comprehensive CloudFormation template that implements complete protection:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
AWSTemplateFormatVersion: '2010-09-09'
Description: 'AWS WAF with CloudFront - OWASP Top 10 Protection'

Parameters:
  ApplicationName:
    Type: String
    Description: Name of the application for resource naming
    Default: 'secure-webapp'
  
  OriginDomainName:
    Type: String
    Description: Origin server domain name
    
  AllowedCountries:
    Type: CommaDelimitedList
    Description: List of allowed country codes
    Default: 'US,CA,GB'

Resources:
  # AWS WAF Web ACL with OWASP Top 10 Protection
  WebApplicationFirewall:
    Type: AWS::WAFv2::WebACL
    Properties:
      Name: !Sub '${ApplicationName}-waf-acl'
      Scope: CLOUDFRONT
      DefaultAction:
        Allow: {}
      Description: 'WAF ACL for OWASP Top 10 protection'
      
      Rules:
        # 1. Rate limiting to prevent brute force attacks
        - Name: RateLimitRule
          Priority: 1
          Statement:
            RateBasedStatement:
              Limit: 2000
              AggregateKeyType: IP
          Action:
            Block: {}
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: !Sub '${ApplicationName}-rate-limit'
            
        # 2. Geographic blocking
        - Name: GeoBlockRule
          Priority: 2
          Statement:
            NotStatement:
              Statement:
                GeoMatchStatement:
                  CountryCodes: !Ref AllowedCountries
          Action:
            Block: {}
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: !Sub '${ApplicationName}-geo-block'
            
        # 3. AWS Managed Rule - Core Rule Set (CRS)
        - Name: AWSManagedRulesCommonRuleSet
          Priority: 3
          OverrideAction:
            None: {}
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesCommonRuleSet
              # Exclude specific rules if needed
              ExcludedRules: []
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: !Sub '${ApplicationName}-common-ruleset'
            
        # 4. SQL Injection Protection
        - Name: AWSManagedRulesSQLiRuleSet
          Priority: 4
          OverrideAction:
            None: {}
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesSQLiRuleSet
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: !Sub '${ApplicationName}-sqli-protection'
            
        # 5. Cross-Site Scripting (XSS) Protection
        - Name: AWSManagedRulesKnownBadInputsRuleSet
          Priority: 5
          OverrideAction:
            None: {}
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesKnownBadInputsRuleSet
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: !Sub '${ApplicationName}-xss-protection'
            
        # 6. Linux Operating System Protection
        - Name: AWSManagedRulesLinuxRuleSet
          Priority: 6
          OverrideAction:
            None: {}
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesLinuxRuleSet
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: !Sub '${ApplicationName}-linux-protection'
            
        # 7. Anonymous IP List
        - Name: AWSManagedRulesAnonymousIpList
          Priority: 7
          OverrideAction:
            None: {}
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesAnonymousIpList
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: !Sub '${ApplicationName}-anonymous-ip'
            
        # 8. Amazon IP Reputation List
        - Name: AWSManagedRulesAmazonIpReputationList
          Priority: 8
          OverrideAction:
            None: {}
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesAmazonIpReputationList
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: !Sub '${ApplicationName}-ip-reputation'

      VisibilityConfig:
        SampledRequestsEnabled: true
        CloudWatchMetricsEnabled: true
        MetricName: !Sub '${ApplicationName}-waf-acl'

  # CloudFront Distribution with WAF Integration
  CloudFrontDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Enabled: true
        Comment: !Sub 'CloudFront distribution for ${ApplicationName} with WAF protection'
        
        # Web ACL Association
        WebACLId: !GetAtt WebApplicationFirewall.Arn
        
        # Origin Configuration
        Origins:
          - Id: !Sub '${ApplicationName}-origin'
            DomainName: !Ref OriginDomainName
            CustomOriginConfig:
              HTTPPort: 80
              HTTPSPort: 443
              OriginProtocolPolicy: https-only
              OriginSSLProtocols:
                - TLSv1.2
                - TLSv1.3
              OriginReadTimeout: 30
              OriginKeepaliveTimeout: 5
        
        # Default Cache Behavior
        DefaultCacheBehavior:
          TargetOriginId: !Sub '${ApplicationName}-origin'
          ViewerProtocolPolicy: redirect-to-https
          AllowedMethods:
            - GET
            - HEAD
            - OPTIONS
            - PUT
            - POST
            - PATCH
            - DELETE
          CachedMethods:
            - GET
            - HEAD
          Compress: true
          
          # Security Headers
          ResponseHeadersPolicyId: !Ref SecurityHeadersPolicy
          
          # Caching Configuration
          CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad  # CachingDisabled for dynamic content
          OriginRequestPolicyId: 88a5eaf4-2fd4-4709-b370-b4c650ea3fcf  # CORS-S3Origin
          
        # Additional Security Configuration
        PriceClass: PriceClass_All  # Global edge locations for maximum protection
        ViewerCertificate:
          AcmCertificateArn: !Ref SSLCertificate
          SslSupportMethod: sni-only
          MinimumProtocolVersion: TLSv1.2_2021

        # Logging Configuration
        Logging:
          Bucket: !GetAtt LoggingBucket.DomainName
          Prefix: 'cloudfront-logs/'
          IncludeCookies: false

  # Security Headers Response Policy
  SecurityHeadersPolicy:
    Type: AWS::CloudFront::ResponseHeadersPolicy
    Properties:
      ResponseHeadersPolicyConfig:
        Name: !Sub '${ApplicationName}-security-headers'
        SecurityHeadersConfig:
          StrictTransportSecurity:
            AccessControlMaxAgeSec: 31536000
            IncludeSubdomains: true
            Override: false
          ContentTypeOptions:
            Override: false
          FrameOptions:
            FrameOption: DENY
            Override: false
          XSSProtection:
            ModeBlock: true
            Protection: true
            Override: false
        CustomHeadersConfig:
          Items:
            - Header: 'Content-Security-Policy'
              Value: "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'; frame-ancestors 'none';"
              Override: false

  # S3 Bucket for CloudFront Logs
  LoggingBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub '${ApplicationName}-cloudfront-logs-${AWS::AccountId}'
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      LifecycleConfiguration:
        Rules:
          - Id: DeleteOldLogs
            Status: Enabled
            ExpirationInDays: 90

  # SSL Certificate (assumes certificate is already created)
  SSLCertificate:
    Type: AWS::CertificateManager::Certificate
    Properties:
      DomainName: !Ref OriginDomainName
      ValidationMethod: DNS
      DomainValidationOptions:
        - DomainName: !Ref OriginDomainName
          HostedZoneId: !Ref HostedZoneId  # You'll need to provide this

Outputs:
  WebACLId:
    Description: 'AWS WAF Web ACL ID'
    Value: !GetAtt WebApplicationFirewall.Arn
    Export:
      Name: !Sub '${ApplicationName}-waf-acl-id'
      
  CloudFrontDomainName:
    Description: 'CloudFront Distribution Domain Name'
    Value: !GetAtt CloudFrontDistribution.DomainName
    Export:
      Name: !Sub '${ApplicationName}-cloudfront-domain'
      
  CloudFrontDistributionId:
    Description: 'CloudFront Distribution ID'
    Value: !Ref CloudFrontDistribution
    Export:
      Name: !Sub '${ApplicationName}-cloudfront-id'

Advanced Rule Customization and Tuning

Custom SQL Injection Detection

While AWS managed rules provide excellent baseline protection, you may need custom rules for application-specific SQL injection patterns:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# Custom SQL Injection Rule Example
CustomSQLiRule:
  Type: AWS::WAFv2::WebACL
  Properties:
    Rules:
      - Name: CustomSQLInjectionRule
        Priority: 10
        Statement:
          OrStatement:
            Statements:
              # Detect SQL keywords in query parameters
              - ByteMatchStatement:
                  SearchString: 'union select'
                  FieldToMatch:
                    AllQueryArguments: {}
                  TextTransformations:
                    - Priority: 1
                      Type: URL_DECODE
                    - Priority: 2
                      Type: LOWERCASE
                  PositionalConstraint: CONTAINS
              
              # Detect SQL comments
              - ByteMatchStatement:
                  SearchString: '--'
                  FieldToMatch:
                    AllQueryArguments: {}
                  TextTransformations:
                    - Priority: 1
                      Type: URL_DECODE
                  PositionalConstraint: CONTAINS
              
              # Detect SQL functions
              - RegexMatchStatement:
                  RegexString: '(?i)(concat|substring|ascii|char|user|database|version)\s*\('
                  FieldToMatch:
                    AllQueryArguments: {}
                  TextTransformations:
                    - Priority: 1
                      Type: URL_DECODE
                    - Priority: 2
                      Type: HTML_ENTITY_DECODE

        Action:
          Block: {}
        VisibilityConfig:
          SampledRequestsEnabled: true
          CloudWatchMetricsEnabled: true
          MetricName: 'custom-sqli-rule'

Advanced XSS Protection

Implement sophisticated XSS detection that goes beyond standard patterns:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# Advanced XSS Detection Rules
AdvancedXSSRules:
  - Name: XSSPatternDetection
    Priority: 11
    Statement:
      OrStatement:
        Statements:
          # JavaScript event handlers
          - RegexMatchStatement:
              RegexString: '(?i)on(load|error|click|mouse|focus|blur|change|submit|reset|select|resize|scroll)='
              FieldToMatch:
                Body: {}
              TextTransformations:
                - Priority: 1
                  Type: URL_DECODE
                - Priority: 2
                  Type: HTML_ENTITY_DECODE
          
          # Script tag variations
          - RegexMatchStatement:
              RegexString: '(?i)<script[^>]*>.*?</script>'
              FieldToMatch:
                Body: {}
              TextTransformations:
                - Priority: 1
                  Type: URL_DECODE
                - Priority: 2
                  Type: HTML_ENTITY_DECODE
          
          # JavaScript pseudo protocol
          - ByteMatchStatement:
              SearchString: 'javascript:'
              FieldToMatch:
                AllQueryArguments: {}
              TextTransformations:
                - Priority: 1
                  Type: URL_DECODE
                - Priority: 2
                  Type: LOWERCASE
              PositionalConstraint: CONTAINS

    Action:
      Block: {}
    VisibilityConfig:
      SampledRequestsEnabled: true
      CloudWatchMetricsEnabled: true
      MetricName: 'advanced-xss-protection'

Monitoring and Alerting Implementation

CloudWatch Dashboard for WAF Metrics

Create comprehensive monitoring to track attack patterns and rule effectiveness:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import boto3
import json
from datetime import datetime, timedelta

def create_waf_dashboard(dashboard_name, web_acl_name, cloudfront_distribution_id):
    """
    Create CloudWatch Dashboard for AWS WAF monitoring
    """
    cloudwatch = boto3.client('cloudwatch')
    
    dashboard_body = {
        "widgets": [
            {
                "type": "metric",
                "x": 0, "y": 0,
                "width": 12, "height": 6,
                "properties": {
                    "metrics": [
                        ["AWS/WAFV2", "AllowedRequests", "WebACL", web_acl_name, "Region", "CloudFront", "Rule", "ALL"],
                        [".", "BlockedRequests", ".", ".", ".", ".", ".", "."]
                    ],
                    "view": "timeSeries",
                    "stacked": False,
                    "region": "us-east-1",
                    "title": "WAF Request Overview",
                    "period": 300
                }
            },
            {
                "type": "metric",
                "x": 12, "y": 0,
                "width": 12, "height": 6,
                "properties": {
                    "metrics": [
                        ["AWS/WAFV2", "BlockedRequests", "WebACL", web_acl_name, "Region", "CloudFront", "Rule", "RateLimitRule"],
                        [".", ".", ".", ".", ".", ".", ".", "CustomSQLInjectionRule"],
                        [".", ".", ".", ".", ".", ".", ".", "AdvancedXSSRule"]
                    ],
                    "view": "timeSeries",
                    "stacked": True,
                    "region": "us-east-1",
                    "title": "Blocked Requests by Rule Type",
                    "period": 300
                }
            },
            {
                "type": "metric",
                "x": 0, "y": 6,
                "width": 24, "height": 6,
                "properties": {
                    "metrics": [
                        ["AWS/CloudFront", "Requests", "DistributionId", cloudfront_distribution_id],
                        [".", "BytesDownloaded", ".", "."],
                        [".", "4xxErrorRate", ".", "."],
                        [".", "5xxErrorRate", ".", "."]
                    ],
                    "view": "timeSeries",
                    "stacked": False,
                    "region": "us-east-1",
                    "title": "CloudFront Performance Metrics",
                    "period": 300
                }
            }
        ]
    }
    
    response = cloudwatch.put_dashboard(
        DashboardName=dashboard_name,
        DashboardBody=json.dumps(dashboard_body)
    )
    
    return response

def create_waf_alarms(web_acl_name, sns_topic_arn):
    """
    Create CloudWatch Alarms for critical WAF events
    """
    cloudwatch = boto3.client('cloudwatch')
    
    # High rate of blocked requests alarm
    blocked_requests_alarm = cloudwatch.put_metric_alarm(
        AlarmName=f'{web_acl_name}-high-blocked-requests',
        ComparisonOperator='GreaterThanThreshold',
        EvaluationPeriods=2,
        MetricName='BlockedRequests',
        Namespace='AWS/WAFV2',
        Period=300,
        Statistic='Sum',
        Threshold=1000.0,
        ActionsEnabled=True,
        AlarmActions=[sns_topic_arn],
        AlarmDescription='Alert when blocked requests exceed threshold',
        Dimensions=[
            {
                'Name': 'WebACL',
                'Value': web_acl_name
            },
            {
                'Name': 'Region',
                'Value': 'CloudFront'
            }
        ]
    )
    
    # SQL injection attack alarm
    sqli_alarm = cloudwatch.put_metric_alarm(
        AlarmName=f'{web_acl_name}-sqli-attack',
        ComparisonOperator='GreaterThanThreshold',
        EvaluationPeriods=1,
        MetricName='BlockedRequests',
        Namespace='AWS/WAFV2',
        Period=300,
        Statistic='Sum',
        Threshold=50.0,
        ActionsEnabled=True,
        AlarmActions=[sns_topic_arn],
        AlarmDescription='Alert on SQL injection attack patterns',
        Dimensions=[
            {
                'Name': 'WebACL',
                'Value': web_acl_name
            },
            {
                'Name': 'Rule',
                'Value': 'CustomSQLInjectionRule'
            }
        ]
    )
    
    return blocked_requests_alarm, sqli_alarm

# Usage example
if __name__ == "__main__":
    dashboard_response = create_waf_dashboard(
        dashboard_name="WAF-Security-Dashboard",
        web_acl_name="secure-webapp-waf-acl",
        cloudfront_distribution_id="E1234567890123"
    )
    
    sns_topic = "arn:aws:sns:us-east-1:123456789012:security-alerts"
    alarms = create_waf_alarms("secure-webapp-waf-acl", sns_topic)
    
    print("Dashboard and alarms created successfully")

Conclusion

AWS WAF integrated with CloudFront provides enterprise-grade web application security that scales automatically and requires minimal operational overhead compared to traditional solutions. By implementing the comprehensive protection strategy outlined in this guide, organizations can effectively defend against OWASP Top 10 vulnerabilities while maintaining high performance and availability.

The cloud-native approach eliminates the complexity of managing infrastructure, patching security software, and scaling protection during attack scenarios. With proper monitoring, alerting, and automated response mechanisms in place, AWS WAF becomes a cornerstone of a robust DevSecOps security strategy.

The combination of AWS managed rules, custom threat detection, and automated response provides multilayered protection that evolves with emerging threats while maintaining the agility required for modern application deployment.

For personalized guidance on implementing AWS WAF and CloudFront security in your DevSecOps environment, connect with Jon Price on LinkedIn.

This post is licensed under CC BY 4.0 by the author.