I was recently involved with setting up a website for a not-for-profit. It’s not often I get hands on keyboards these days, so it’s been fun playing with some of the latest Azure features.
The set-up was pretty simple – a WordPress website running on App Service, with Azure Front Door sat in front of it. Everything was working fine until the developers started reporting a curious error, some calls to WordPress were mysteriously failing with an error:
“This request has been denied by the firewall.”
No explanation. No debugging information, just something that pointed me in the vague direction of Azure Front Door. The quest was on to find the culprit.
The first challenge was how to even enable debugging on the firewall. After some hunting, I discovered the setting. If you browse to your Azure Front Door, you’ll see the option for “Diagnostic settings”.
Inside there, click:
You’ll see the Diagnostics settings pane:
Select the FrontdoorAccessLog, FrontdoorWebApplicationFirewallLog and AllMetrics. Then select “Send to Log Analytics” and select your subscription and Log Analytics workspace. If you don’t have a workspace, you can create one. Hit Save.
Give it a minute to activate and then browse to the page that is causing the issue. Now it’s time to find out which rule is causing the problem and fix it.
Open your Log Analytics workspace and type the following query into the query editor:
| where ResourceType == "FRONTDOORS" and Category == "FrontdoorWebApplicationFirewallLog"
| where action_s == "Block"
You should see your failed request listed in the results below:
If you expand out one of the results, you will be able to see the full details of the failed request:
Now the fun begins. Unfortunately, the diagnostics information is not particularly helpful. We can see from here the URL that is causing the problem; in this case it is:
We can also see the rule which is causing it to fail:
And we can see what it does not like:
matchVariableValue Get New Password
But what does this mean and how do we fix it? The simplest solution is to disable the rule, although this is not advisable. To fix it properly is slightly more involved.
The first thing to understand is how the Web Application Firewall in Azure works. There are several default rules which you can configure which look for malicious actions being taken against your site.
The firewall checks for malicious content in:
- Request Headers (items such as the User-Agent, etc)
- Request cookies (cookies sent by the browser)
- Request query string arguments (http://domain.com/?key=value)
- Request POST arguments (data submitted by forms)
The first job is to work out which one of these is causing the problem. The log (helpfully) does not tell you and you must work it our yourself. Your clues are contained within the “details_matches_s” and “requestUri_s” fields in the log. The details show the value of the match, not the name of the field. To fix the problem, as we will see later, it is the name of the field you need.
Query String Arguments
The easiest to spot are the query string arguments. If the contents of the “details_matches_s” also appears within the “requestUri_s”, it is a query string. An example is shown below:
We can see here:
is part of the load-styles.php URI, as shown here:
If we URL decode this (using something like https://www.urldecoder.org/) we’ll see the following:
So, the name of the field that is causing the problem is:
Request Post Arguments
Post request arguments are much harder to fix. This is because, again, all we can see in the logs are the value of the troublesome field, not the name of it. An example is shown here:
Once you have set it up and it is capturing traffic
- Look to see your failed request and click on it
- In the request pane, click on WebForms button
- Scroll down the list of Values on the right, trying to find the value which was logged
- You will see the name to the left of it
In this example, you can see the name of the field is “wpcf7-mail[subject]”
Request Header Arguments and Cookies
For these two, simply follow the instructions for Request Post Arguments, but in the request pane, click the Headers or Cookies button as appropriate.
Fixing the error
Once you have the name of the rule which is causing the problem, along with the name of the troublesome field, fixing it is trivially simple.
In the Azure portal, open your Front Door WAF Policy and click on “Managed Rules” and then “Manage Exclusions”:
You will then see the Managed rules – All exclusions pane. Click Add:
You will then see the Rule exclusion pane. In here you’ll see:
- The rule set you want this exception to apply to
- The rule set (or leave blank to apply to all rule sets)
- The specific rule (quite often when you select an individual rule, it will then trip again on another rule in this set, so it is sometimes easier to apply the exception to the group)
- Match variable (this is the portion of the request which triggered the failure: header, post, cookie, query string)
- Operator (standard contains, equals etc)
- Selector (the name of the field you worked out above)
Populate these as appropriate, and if you want WordPress to work properly, you will end up with something that looks like this:
When you are finished click “Save” at the bottom, wait a couple of minutes and your exclusions will be deployed. Quite often you will put one exclusion in and immediately trigger another, so you might have to do a few rounds to get the original error to go away. Each time you trigger the failure, you must wait 3-4 minutes for the failure to make it to the log, so it is quite a painful process, unfortunately.
There is no ability to put an exclusion on a particular page, or from a particular IP address, you have to go to this level of detail.
In time, we may be able to add the match variable type and the field name to the log, which would make the whole process even more straightforward.