Skip to content

Why does AWS WAF block my request or respond with a 403 Forbidden error?

6 minute read
7

I want to identify the AWS WAF rule that blocks my request or responds with a 403 Forbidden error.

Short description

By default, AWS WAF returns a "403 Forbidden" error for requests that match AWS WAF rules with the Block action. If you set up custom responses for Block actions, then AWS WAF returns your configured response.

To troubleshoot the "403 Forbidden" error, use Sampled requests or AWS WAF logs. Identify the AWS WAF rule or rule group that blocks the request. Then, modify the rule to allow your request.

Resolution

Use sampled requests

If AWS WAF blocked your request within the past 3 hours, then you can view a sample of the blocked web requests. If AWS WAF blocked your request more than 3 hours ago, then resend the same request to generate a new sampled request.

In the Sampled requests table, review the following columns:

  • To identify the request, review the Source IP and URI columns.
  • To identify the rule or rule group that matches the request, review the Metric name column. If a rule group is blocking the request, then use the Rule inside rule group column to identify the rule.
  • To confirm that the rule is set to Block, review the Action column.

Use AWS WAF logs

Note: If you didn't activate AWS WAF logging at the time of your request, then turn on AWS WAF logging and resend the same request.

Use the queries in your AWS WAF logs to identify the blocked requests. To query AWS WAF logs that you store in Amazon CloudWatch Logs, use Amazon CloudWatch Logs Insights queries. To query AWS WAF logs that you store in Amazon Simple Storage Service (Amazon S3), use Amazon Athena queries.

Query AWS WAF logs with CloudWatch Logs Insights

To get the top 10 terminating rules, run the following query:

fields terminatingRuleId
| stats count() as requestCount by terminatingRuleId
| sort requestCount desc
| limit 10

To summarize requests that AWS WAF blocked by client IP address, country, URI, and rule, run the following query:

fields httpRequest.clientIp as ClientIP, httpRequest.country as Country, httpRequest.uri as URI, terminatingRuleId as Rule
| filter action = "BLOCK"
| stats count() as RequestCount by Country, ClientIP, URI, Rule
| sort RequestCount desc

Note: In the output, the terminatingRuleId field identifies the AWS WAF rule or rule group that blocks the request.

Query AWS WAF logs with Athena

For AWS WAF logs that you store in an Amazon S3 bucket, use Athena to create an AWS WAF table that queries logs and filters details. For more information, see Query AWS WAF logs. Then, run queries on the table.

For example, to view the number of requests that AWS WAF blocked based on client IP address and country, run the following query:

SELECT  "httprequest"."clientip"
,"count"(*) "count"  
, "httprequest"."country"
FROM
waf_logs
WHERE ("action" LIKE 'BLOCK')
GROUP BY "httprequest"."clientip", "httprequest"."country"
ORDER BY "count" DESC

Identify the cause of a 403 from a single log entry 

The previous CloudWatch Logs Insights queries return aggregated counts that help you find which rules block traffic. To inspect a single blocked request, run a query that returns raw log entries instead of aggregated counts. For example, to retrieve the most recent requests blocked by a specific rule, run the following query: 

fields @timestamp, action, terminatingRuleId, httpRequest.clientIp, @message  
| filter action = "BLOCK" and terminatingRuleId = "RULE_NAME"  
| sort @timestamp desc  
| limit 20 

Note: Replace RULE_NAME with a rule ID that appeared in the aggregated results. For example, AWS-AWSManagedRulesSQLiRuleSet. The @message field of each result is the full JSON log entry.

Review the following fields in the entry to identify the cause of the 403 response:  

  • The Action field confirms that the request returned a 403 response when the value is Block

  • The terminatingRuleId field shows the rule or rule group that matched and stopped evaluation. 

  • The terminatingRuleType field indicates whether the match came from a MANAGED_RULE_GROUP, RATE_BASED rule, or REGULAR custom rule. 

  • The terminatingRuleMatchDetails field shows the matched portion of the request for SQLi or XSS rules, including the location, condition type, and matched data. 

  • The ruleGroupList field identifies the specific rule inside a managed rule group that produced the terminating action. 

  • The Labels field contains labels that the rule or rule group attached to the request, which helps identify managed rule group matches.

  • The httpRequest.uri, httpRequest.args, and httpRequest.headers fields show the part of the request that the rule inspected. 

The following example shows a log entry for a request that AWS WAF blocked. The AWS Managed Rules SQL database rule group matched a SQLi pattern in the query string:

{ 
  "action": "BLOCK", 
  "terminatingRuleId": "AWS-AWSManagedRulesSQLiRuleSet", 
  "terminatingRuleType": "MANAGED_RULE_GROUP", 
  "ruleGroupList": [{ 
    "ruleGroupId": "AWS#AWSManagedRulesSQLiRuleSet", 
    "terminatingRule": { 
      "ruleId": "SQLi_QUERYARGUMENTS", 
      "action": "BLOCK" 
    } 
  }], 
  "terminatingRuleMatchDetails": [{ 
    "conditionType": "SQL_INJECTION", 
    "location": "QUERY_ARGUMENTS", 
    "matchedData": ["'", "or", "1"] 
  }], 
  "httpRequest": { 
    "clientIp": "203.0.113.42", 
    "uri": "/products", 
    "args": "id=1' OR '1'='1" 
  } 
} 

In this example, the terminatingRuleId is AWS-AWSManagedRulesSQLiRuleSet and the SQLi_QUERYARGUMENTS rule inside the rule group matched a SQL injection pattern. The terminatingRuleMatchDetails field shows that the match was in the query arguments and the matched tokens were ', or, and 1, which together appear in httpRequest.args (id=1' OR '1'='1).

The following example shows a log entry for a request that AWS WAF blocked. The source IP address is on the Amazon IP reputation list:

{  
  "action": "BLOCK",  
  "terminatingRuleId": "AWS-AWSManagedRulesAmazonIpReputationList",  
  "terminatingRuleType": "MANAGED_RULE_GROUP",  
  "ruleGroupList": [{  
    "ruleGroupId": "AWS#AWSManagedRulesAmazonIpReputationList",  
    "terminatingRule": {  
      "ruleId": "AWSManagedIPReputationList",  
      "action": "BLOCK"  
    }  
  }],  
  "httpRequest": {  
    "clientIp": "198.51.100.42",  
    "uri": "/api/login"  
  },  
  "labels": [  
    { "name": "awswaf:managed:aws:amazon-ip-list:AWSManagedIPReputationList" }  
  ]  
} 

In this example, the terminatingRuleId is AWS-AWSManagedRulesAmazonIpReputationList and the labels array confirms the match (awswaf:managed:aws:amazon-ip-list:AWSManagedIPReputationList). The source IP 198.51.100.42 appeared on Amazon's IP reputation list at the time of the request. 

For requests blocked by a geo-match, rate-based, or custom rule, use the same approach. The terminatingRuleId combined with httpRequest.clientIp, httpRequest.country, and the labels array identifies which rule blocked the request and why.

Modify the AWS WAF rule to allow your request

If the blocking rule is in an AWS Managed Rules rule group, then customize the rule behavior.

If the blocking rule is a custom rule, then update your rule parameters to use a rule statement to allow the request.

Related information

How do I turn on AWS WAF logging and send logs to CloudWatch, Amazon S3, or Firehose?

How do I analyze AWS WAF logs in CloudWatch?

How to customize behavior of AWS Managed Rules for AWS WAF

AWS OFFICIALUpdated 3 months ago