Recently Ive been helping with a few implementations for Azure Frontdoor in front of API Management and I wanted to talk a little about the WAF implementation. WAF can help protect your API if its running through Frontdoor first and you can apply WAF rules before your API runs so you can off load some of the DDOS protection and also use the WAF rules to check for vulnerabilities before it gets to your code. This is all great stuff but the documentation is pretty high level and ive had a few people ask about this so I thought it would be good to put together a few postman test examples to show what the WAF can and can not do.
In this first post ill talk about using the original Frontdoor SKU with WAF and then ill do a followup part 2 where we will look at the new Frontdoor Premium SKU and see what extra things it can do.
First lets take a quick look at the architecture which is shown below.
I am just going to use the out of the box Echo API which API Management gives you which just echo’s back the request you sent it. Im then going to put Frontdoor with routing rules to forward messages to APIM and then test it with Postman. I will configure the WAF on frontdoor and then send a bunch of postman requests.
In this post I want to focus on the behaviours to expect in your postman tests which will show what Frontdoor and WAF will do. There isnt really any custom configuration of the WAF. Ive just added it as a policy on the Frontdoor and ive got the settings on the policy as shown below.
In this post I am using the Microsoft_DefaultRuleSet_1.1 or DSR1.1.
Tests
In the test cases I want to show which scenarios will work and your WAF will protect your API and I also want to show which scenarios it will not cover.
Check GET request works – Pass
This is a basic test to just check the Get method on the echo API will work
Expected Behaviour | We expect an HTTP 200 response |
Actual Behaviour | This should work fine and WAF will let this request pass through |
Request:
GET /echo/resource?param1=sam1ple¶m2=1 HTTP/1.1
Host: {mikeshost}.com
Ocp-Apim-Subscription-Key: {MikesKey}
SQL Injection in Query String should fail with apostrophe – Pass
This test will use an ‘ character in the query string parameter which should trigger a SQL injection WAF rule to block the request.
Expected Behaviour | The WAF should block the request |
Actual Behaviour | Request blocked by WAF with HTTP 403 response |
Request:
GET /echo/resource?param1=sam1ple¶m2=' HTTP/1.1
Host: {mikeshost}.com
Ocp-Apim-Subscription-Key: {MikesKey}
SQL Injection in Query String should fail with 1=1 – Pass
This is another test which should trigger the SQL injection rule. We will use a 1=1 clause in the SQL query which should trigger the rule.
Expected Behaviour | The WAF should block the request |
Actual Behaviour | Request blocked by WAF with HTTP 403 response |
Request:
GET /echo/resource?param1=sam1ple¶m2=SELECT * FROM Users WHERE UserId = 105 OR 1=1; HTTP/1.1
Host: {mikeshost}.com
Ocp-Apim-Subscription-Key: {MikesKey}
Check PUT request works – Pass
This is a basic test for the ECHO api put operation to check it works.
Expected Behaviour | This should be successful and not blocked by WAF and should return a response |
Actual Behaviour | HTTP 200 and we are displayed the request we sent |
Request:
PUT /echo/resource HTTP/1.1
Host: {mikeshost}.com
Ocp-Apim-Subscription-Key: {MikesKey}
Content-Type: application/json
Content-Length: 100
{
"vehicleType": "train",
"maxSpeed": 125,
"avgSpeed": 90,
"speedUnit": "mph"
}
SQL Injection in Query String should fail with apostrophe – Pass
In this case I am sending a PUT request but I will include an apostrophe in a query string parameter which should trigger the WAF rules.
Expected Behaviour | WAF will block the request |
Actual Behaviour | HTTP 403 and a message that WAF blocks the request |
Request:
PUT /echo/resource?test=' HTTP/1.1
Host: {mikeshost}.com
Ocp-Apim-Subscription-Key: {MikesKey}
Content-Type: application/json
Content-Length: 100
{
"vehicleType": "train",
"maxSpeed": 125,
"avgSpeed": 90,
"speedUnit": "mph"
}
SQL Injection in Query String should fail with 1=1 – Pass
In this case I am replicating the test we did earlier but this time with a PUT request rather than the GET request. I am including the 1=1 to try to trigger the SQL injection rule.
Expected Behaviour | WAF will block the request |
Actual Behaviour | HTTP 403 with a message that WAF blocks the request |
Request:
PUT /echo/resource?test=SELECT * FROM Users WHERE UserId = 105 OR 1=1; HTTP/1.1
Host: {mikeshost}.com
Ocp-Apim-Subscription-Key: {MikesKey}
Content-Type: application/json
Content-Length: 100
{
"vehicleType": "train",
"maxSpeed": 125,
"avgSpeed": 90,
"speedUnit": "mph"
}
SQL Injection in plain text body should fail with 1=1 – Fail
In this request we are using a plain text request with a SQL statement which we hope will trigger the WAF rule.
Desired Behaviour | We would like the WAF rule to trigger and block the request |
Actual Behaviour | The request is not blocked and is forwarded to APIM and we get a 200 response code and the text we sent is returned back |
Request:
PUT /echo/resource HTTP/1.1
Host: {mikeshost}.com
Ocp-Apim-Subscription-Key: {mikeskey}
Content-Type: text/plain
Content-Length: 46
SELECT * FROM Users WHERE UserId = 105 OR 1=1;
SQL Injection in Json body should fail with 1=1 – Fail
In this test we will send a json message with a sql statement in the json message.
Desired Behaviour | We hope that this will trigger the WAF rule and the request is blocked |
Actual Behaviour | The request is not blocked and it is forwarded to the APIM where the Echo API is returns the message to us |
Request:
PUT /echo/resource HTTP/1.1
Host: {mikeshost}.com
Ocp-Apim-Subscription-Key: {mikeskey}
Content-Type: application/json
Content-Length: 143
{
"vehicleType": "train",
"maxSpeed": 125,
"avgSpeed": 90,
"speedUnit": "SELECT * FROM Users WHERE UserId = 105 OR 1=1;"
}
SQL Injection in form body should fail – Pass
In this request we will send a x-www-form-urlencoded request to the API. The request will include a SQL injection in the SQL statement which we hope will trigger the SQL injection rules.
Expected Behaviour | The request is blocked by WAF |
Actual Behaviour | The request is blocked by WAF and we get an HTTP 403 response |
Request:
PUT /echo/resource HTTP/1.1
Host: {mikeshost}.com
Ocp-Apim-Subscription-Key: {mikeskey}
Content-Type: application/x-www-form-urlencoded
Content-Length: 74
SQL=SELECT%20*%20FROM%20Users%20WHERE%20UserId%20%3D%20105%20OR%201%3D1%3B
XSS in form parameter should fail – Pass
In this request we will send an x-www-form-urlencoded request which will contain a potential XSS attack which we hope will trigger the WAF rules.
Expected Behaviour | The request is blocked by WAF |
Actual Behaviour | We get an http 403 response and the request is blocked by WAF |
Request:
PUT /echo/resource HTTP/1.1
Host: {mikeshost}.com
Ocp-Apim-Subscription-Key: {mikeskey}
Content-Type: application/x-www-form-urlencoded
Content-Length: 93
test=%3Cscript%3Ealert(%E2%80%9CThis%20is%20a%20XSS%20Exploit%20Test%E2%80%9D)%3C%2Fscript%3E
XSS in Json body should fail – Fail
In this test we will send a request which is a json message which contains text which could be a potential XSS attack. We hope that this will trigger the WAF rule.
Desired Behaviour | The request is blocked by WAF |
Actual Behaviour | The request is not blocked and is forwarded to APIM and it is echo’d back to us and we get an HTTP 200 response. |
Request:
PUT /echo/resource HTTP/1.1
Host: {mikeshost}.com
Ocp-Apim-Subscription-Key: {mikeskey}
Content-Type: application/json
Content-Length: 149
{
"vehicleType": "train",
"maxSpeed": 125,
"avgSpeed": 90,
"speedUnit": "<script>alert(“This is a XSS Exploit Test”)</script>"
}
Summary
In this post I wanted to help you easily see what you can do with the out of the box WAF rules and also what types of request it will not block. The documentation is quite vague on describing this so I thought that some examples showing some of the common use cases would help to visualise this.
The key takeaways from this post are that you can effectively use the WAF rules to check for SQL injection and XSS attempts in the query string and in x-www-form-urlencoded requests but the rules can not check for json message bodies.
If you want to checkout my postman collection to try this for yourself you can get it from here: