Essential App Protect API User’s Guide

Prerequisites

F5 Cloud Services provides a platform for a host of different delivery, security, and insight services. This platform and all of the services use an API-first approach, meaning the API is developed first, and then the portal or service is developed using the API. As a part of F5 Cloud Services, Essential App Protect uses many of the underlying platform resources and requests as a basis for the services it provides. Prior to working with the API for Essential App Protect and this guide, you should have a reasonable understanding of the first three chapters of the F5 Cloud Services - API Guidelines.

In the following sections we will deploy Essential App Protect using the API implemented in Postman, and we’ll show a number of different capabilities using the API. You can download the Postman collection for the Essential App Protect service API here: Essential App Protect Collection.

Create a new Service Instance

Essential App Protect provides instant, out-of-the-box protection from common web exploits, malicious IPs, and coordinated attack types. It is placed in front of your web application and verifies that both incoming requests and outgoing responses follow a set of rules (the security policy) to ensure the safety and integrity of the web application and all data passed back and forth. Think of Essential App Protect as a wall around your application with a single gate. All traffic must pass through that gate, and bad or problematic traffic either gets blocked, logged, or cleaned based on the policy you create. That is why this type of services is sometimes called a web application firewall (WAF).

The steps to setup a new service instances are as follows:

  • Log into the platform and subscribe to the service
  • Add an SSL/TLS certificate for https data encryption
  • Configure a JSON payload for your application and its security policy
  • Create the service instance and activate it
  • Force all traffic through Essential App Protect
  • Add Essential App Protect IPs to your allow list as a trusted client whitelist

Validate Variables in Postman

The Postman collection makes use of variables so that you don’t need to edit the requests for things like username, password, and account_id. Before executing the requests in the sections below, ensure that your variables are correctly set in Postman. First select Edit under the F5 Essential App Protect collection menu.

_images/CS-EAP-Edit.Variables.png

Next select the Variables tab and edit the last five variables as follows:

  • USERNAME and PASSWORD: Enter the information you used to create your Cloud Services account.
  • SERVICE_NAME: This a name for this service instance. It will typically be related to the name of the application you are protecting.
  • PROTECTED_APP: Enter the fully qualified domain name (FQDN) for the application you want to protect.
  • APP_ENDPOINT: Enter the IP address of the endpoint for your application. If you have multiple endpoints, you can edit the JSON body schema to list multiple endpoints and possibly multiple regions.
_images/CS-EAP-Set.Variables.png

You can also see that there are two other variables, HOSTNAME and API_VERSION that are already set. These variables are used in all the calls so that this request in Postman:

POST https://{{HOSTNAME}}/{{API_VERSION}}/svc-auth/login

will have the variables replaced by their respective values resulting in the fully-specified URL:

POST https://api.cloudservices.f5.com/v1/svc-auth/login

When using the API outside of the supplied Postman collection, you’ll need to use the full URL.

If you’re using the supplied Postman, you will find all the request used in the following sections in a subfolder called Create New Essential App Protect Service.


Login and Get the Account ID

– Login and get an access token (Postman: Login).

POST https://api.cloudservices.f5.com/v1/svc-auth/login

– Get the primary account id (Postman: Get Account Details).

GET https://api.cloudservices.f5.com/v1/svc-account/user

If this is the first time you are creating a service instance for Essential App Protect, subscribe to the Essential App Protect catalog using catalog_id “c-aa9N0jgHI4” (Postman: Subscribe WAF catalog).

POST https://api.cloudservices.f5.com/v1/svc-account/accounts/{{primary_account_id}}/catalogs

For details on these requests, see the section, 3.6. API Basics for Services in the API Guidelines document.

Add SSL/TLS Certificate

If your application encrypts data between server and browser (uses HTTPS), then you must add an SSL or a TLS certificate so that Essential App Protect can work with your application’s encrypted communications. In the payload, you will need to add your certificate information in the certificate value, and similarly update the private_key and certificate_chain values if you have them. The id in the response JSON uniquely identifies this certificate. In the Postman implementation, it will be stored in the CERTIFICATE_ID variable for use in later requests.

Postman: Add Certificate to Account

POST https://api.cloudservices.f5.com/v1/svc-certificates/certificates

– PAYLOAD

{
    "account_id": "a-aaQgt6MlaD",
    "certificate": "-----BEGIN CERTIFICATE-----\n ... -----END CERTIFICATE-----\n",
    "private_key": "-----BEGIN RSA PRIVATE KEY-----\n ... -----END RSA PRIVATE KEY-----\n",
    "certificate_chain": "-----BEGIN CERTIFICATE-----\n ... -----END CERTIFICATE-----\n"
}

– RESPONSE

{
    "id": "cert-aaQgtCI-Px"
}

Create Essential App Protect Service Subscription Instance

This section will create an Essential App Protect configuration (subscription instance) for your application. Before you can send this request, you must modify the JSON in the payload of the request to provide specifics for your configuration. Below are the modification steps, followed by an example.

Note

If you are using the Postman script, the environment variables will correctly setup the JSON payload; however, the following information may be useful to help you understand other options for setting up your application instance.

  1. Update the service_instance_name. It can be any name that you will associate with this service instance with the application you are protecting. For example: “service_instance_name”: “My Test Site”.

  2. Under the application context, you will find the fqdn variable that will specify your public application domain that you want to protect. For example: “fqdn”: “app.example.com” - Change the value to your FQDN.

  3. Next you will see both the http and https sections. If you your app does not use https, then set enabled in the https section to false. However, if your app uses https, then set enabled to true, add the tls section, and set certificate_id to the value returned when you added your SSL or TLS certificate in the previous section. This is done for you in the Postman implementation if you use the appropriate HTTP or HTTPS request.

    Note

    The Postman script provides two create subscription requests: one for HTTP and the other for HTTPS. The only differences are the ones described in step c above.

  4. Update the AWS deployment region that is closest to your application.

    "waf_regions": {
        "aws": {
            "us-east-1": {
    

    If “us-east-1” is not the correct region for your application, change the value to the appropriate region name from the table below.

    AWS Region Region Name
    US East (N. Virginia) us-east-1
    US East (Ohio) us-east-2
    US West (Oregon) us-west-2
    Europe (Frankfurt) eu-central-1
    Europe (London) eu-west-2
    Europe (Paris) eu-west-3
    Asia Pacific (Tokyo) ap-northeast-1
    Asia Pacific (Singapore) ap-southeast-1
    Asia Pacific (Sydney) ap-southeast-2
    Canada (Central) ca-central-1
  5. Update your end-point configuration:

    • End-point address - you can choose between two options, application end-point via domain or IP address.

      1. For a domain address, change the domain to your end-point DNS name - “dns_name”: “dualstack.a8cf16a61a1b211e982f00a3810f08f3-2050161391.eu-west-1.elb.amazonaws.com”
      2. For IP addresses, delete the domain shown and replace it with an IP specification – “ips”:[“192.168.1.1”] for a single endpoint or “ips”: [“192.168.2.1”, “192.168.1.2”] for multiple endpoints.
    • Port – specify the port used for your application; for example: “port” :80

    Note

    You can specify multiple endpoints in your region, and you can also specify multiple regions by adding them to the JSON script in the body section.

  6. The Policy section of the payload JSON contains the options used by Essential App Protect when protecting your application. You can change these options to correspond with the way you want your application protected prior to issuing this request to create the instance, and you can make changes to the policy later with the update subscription API request or in the portal.

Once the request is sent, the response JSON will contain the subscription_id for this service instance. This value will be required for other requests that are specific to this service instance.

Postman: Create subscription HTTPS (with SSL or TLS) or Postman: Create subscription HTTP (without SSL or TLS)

POST https://api.cloudservices.f5.com/v1/svc-subscription/subscriptions

– PAYLOAD

{
    "account_id": "a-aaQgt6MlaD",
    "catalog_id": "c-aa9N0jgHI4",
    "service_type": "waf",
    "service_instance_name": "{{SERVICE_NAME}}",
    "configuration": {
        "waf_service": {
            "application": {
                "fqdn": "{{PROTECTED_APP}}",
                "http": {
                    "enabled": true,
                    "port": 80
                },
                "https": {
                    "enabled": true,
                    "port": 443,
                    "tls": {
                        "certificate_id": "{{CERTIFICATE_ID}}"
                    }
                },
                "waf_regions": {
                    "aws": {
                        "us-west-2": {
                            "endpoint": {
                                "http": {
                                    "enabled": true,
                                    "port": 8080
                                },
                                "https": {
                                    "enabled": true,
                                    "port": 4443
                                },
                                "ips": [
                                    "{{APP_ENDPOINT}}"
                                ]
                            }
                        }
                    }
                },
                "description": "Example Application",
                "additional_fqdns": [
                    "app.{{PROTECTED_APP}}"
                ],
                "protected_uris": [],
                "unprotected_uris": []
            },
            "industry": "finance",
            "policy": {
                "encoding": "utf-8",
                "compliance_enforcement": {
                    "data_guard": {
                        "enabled": true,
                        "cc": true,
                        "ssn": true
                    },
                    "sensitive_parameters": {
                        "enabled": true,
                        "parameters": [
                            "password",
                            "creditcard"
                        ]
                    }
                },
                "high_risk_attack_mitigation": {
                    "enabled": true,
                    "enforcement_mode": "blocking",
                    "signature_enforcement": {
                        "enabled": true
                    },
                    "allowed_methods": {
                        "enabled": true,
                        "methods": [
                            {
                                "name": "POST",
                                "contains_http_data": true
                            },
                            {
                                "name": "HEAD",
                                "contains_http_data": false
                            },
                            {
                                "name": "GET",
                                "contains_http_data": false
                            }
                        ]
                    },
                    "disallowed_file_types": {
                        "enabled": true,
                        "file_types": [
                            "exe",
                            "com",
                            "bat",
                            "dll"
                        ]
                    },
                    "api_compliance_enforcement": {
                        "enabled": true
                    },
                    "http_compliance_enforcement": {
                        "enabled": true
                    },
                    "websocket_compliance_enforcement": {
                        "enabled": true
                    },
                    "geolocation_enforcement": {
                        "enabled": true,
                        "disallowed_country_codes": [
                            "AF",
                            "BY"
                        ]
                    },
                    "ip_enforcement": {
                        "enabled": true,
                        "ips": [
                            {
                                "address": "1.2.3.4",
                                "description": "This is an app scanner",
                                "action": "block",
                                "log": true
                            },
                            {
                                "address": "1.2.3.5",
                                "description": "some description",
                                "action": "allow",
                                "log": false
                            }
                        ]
                    }
                },
                "malicious_ip_enforcement": {
                    "enabled": true,
                    "enforcement_mode": "blocking",
                    "ip_categories": [
                        {
                            "name": "tor_proxies",
                            "block": true,
                            "log": true
                        },
                        {
                            "name": "cloud_services",
                            "block": false,
                            "log": true
                        }
                    ]
                },
                "threat_campaigns": {
                    "enabled": true,
                    "enforcement_mode": "blocking",
                    "campaigns": [
                        {
                            "id": "cmp177c3bc27c2545ce8571242f1b2022a4",
                            "enabled": false
                        },
                        {
                            "id": "cmp177c3bc27c2545ce8571242f1b2022a5",
                            "enabled": true
                        }
                    ]
                }
            }
        }
    }
}

– RESPONSE

{
    "subscription_id": "s-aawgtryfof",
    "account_id": "a-aaQgt6MlaD",
    "user_id": "u-aaiJJFFvZE",
    "catalog_id": "c-aa9N0jgHI4",
    "service_instance_id": "waf-aagoB-gtVq",
    "status": "DISABLED",
    "service_instance_name": "Example Application",
    "deleted": false,
    "service_type": "waf",
    "configuration": {
        "waf_service": {
            "application": {
                "additional_fqdns": [
                    "app.example.com"
                ],
                "description": "Example Application",
                "fqdn": "example.com",
                "http": {
                    "enabled": true,
                    "port": 80
                },
                "https": {
                    "enabled": true,
                    "port": 443,
                    "tls": {
                        "certificate_id": "cert-aaQgtCI-Px"
                    }
                },
                "waf_regions": {
                    "aws": {
                        "us-west-2": {
                            "endpoint": {
                                "http": {
                                    "enabled": true,
                                    "port": 8080
                                },
                                "https": {
                                    "enabled": true,
                                    "port": 4443
                                },
                                "ips": [
                                    "93.184.216.34"
                                ]
                            }
                        }
                    }
                }
            },
            "industry": "finance",
            "policy": {
                "compliance_enforcement": {
                    "data_guard": {
                        "cc": true,
                        "enabled": true,
                        "ssn": true
                    },
                    "sensitive_parameters": {
                        "enabled": true,
                        "parameters": [
                            "password",
                            "creditcard"
                        ]
                    }
                },
                "encoding": "utf-8",
                "high_risk_attack_mitigation": {
                    "allowed_methods": {
                        "enabled": true,
                        "methods": [
                            {
                                "contains_http_data": true,
                                "name": "POST"
                            },
                            {
                                "contains_http_data": false,
                                "name": "HEAD"
                            },
                            {
                                "contains_http_data": false,
                                "name": "GET"
                            }
                        ]
                    },
                    "api_compliance_enforcement": {
                        "enabled": true
                    },
                    "disallowed_file_types": {
                        "enabled": true,
                        "file_types": [
                            "exe",
                            "com",
                            "bat",
                            "dll"
                        ]
                    },
                    "enabled": true,
                    "enforcement_mode": "blocking",
                    "geolocation_enforcement": {
                        "disallowed_country_codes": [
                            "AF",
                            "BY"
                        ],
                        "enabled": true
                    },
                    "http_compliance_enforcement": {
                        "enabled": true
                    },
                    "ip_enforcement": {
                        "enabled": true,
                        "ips": [
                            {
                                "action": "block",
                                "address": "1.2.3.4",
                                "description": "This is an app scanner",
                                "log": true
                            },
                            {
                                "action": "allow",
                                "address": "1.2.3.5",
                                "description": "some description",
                                "log": false
                            }
                        ]
                    },
                    "signature_enforcement": {
                        "enabled": true
                    },
                    "websocket_compliance_enforcement": {
                        "enabled": true
                    }
                },
                "malicious_ip_enforcement": {
                    "enabled": true,
                    "enforcement_mode": "blocking",
                    "ip_categories": [
                        {
                            "block": true,
                            "log": true,
                            "name": "tor_proxies"
                        },
                        {
                            "block": false,
                            "log": true,
                            "name": "cloud_services"
                        }
                    ]
                },
                "threat_campaigns": {
                    "campaigns": [
                        {
                            "enabled": false,
                            "id": "cmp177c3bc27c2545ce8571242f1b2022a4"
                        },
                        {
                            "enabled": true,
                            "id": "cmp177c3bc27c2545ce8571242f1b2022a5"
                        }
                    ],
                    "enabled": true,
                    "enforcement_mode": "blocking"
                }
            }
        }
    },
    "create_time": "2020-04-29T23:37:25.618698Z",
    "update_time": "2020-04-29T23:37:25.618698Z",
    "cancel_time": null,
    "end_time": null
}

Activate the Essential App Protect Service

Use the activate endpoint to deploy the Essential App Protect instance for your application. You should see that your status is ACTIVE and a service_state which will likely be either UNDEPLOYED or DEPLOYING, because it will take a few minutes to deploy. You can check the status of the deployment with the status endpoint, checking for the service_state to become DEPLOYED. Note that {{SUBSCRIPTION_ID}} in both requests is the placeholder for the actual subscription ID. The Postman collection takes care of this substitution, but for other instances, you will need to do the substitution before making the request.

Postman: Subscription Activate

POST https://api.cloudservices.f5.com/v1/svc-subscription/subscriptions/{{SUBSCRIPTION_ID}}/activate

– RESPONSE

{
   "status": "ACTIVE",
   "service_state": "DEPLOYING",
   "subscription_id": "s-aawgtryfof"
}

Postman: Subscription Status

GET https://api.cloudservices.f5.com/v1/svc-subscription/subscriptions/{{SUBSCRIPTION_ID}}/status

– RESPONSE

{
   "status": "ACTIVE",
   "service_state": "DEPLOYED",
   "subscription_id": "s-aawgtryfof"
}

Get and Use a CNAME Value to Start Protecting Your Application

Now that you have a working Essential App Protect service instance, you need to direct your application’s web traffic through your new service so that it can monitor and/or block malicious traffic. You can get the CNAME value for newly activated Essential App Protect Service instance by requesting its configuration. The CNAME value will have been added as part of the activation. Be sure to substitute the correct subscription id in the request URL in place of {{SUBSCRIPTION_ID}} if you are not using the Postman script.

Postman: Get Subscription

GET https://api.cloudservices.f5.com/v1/svc-subscription/subscriptions/{{SUBSCRIPTION_ID}}

– RESPONSE

{
    "subscription_id": "s-aawgtryfof",
    "account_id": "a-aaQgt6MlaD",
    "user_id": "u-aaiJJFFvZE",
    "catalog_id": "c-aa9N0jgHI4",
    "service_instance_id": "waf-aagoB-gtVq",
    "status": "ACTIVE",
    "service_instance_name": "Example Application",
    "deleted": false,
    "service_type": "waf",
    "configuration": {
        "details": {
            "CNAMEValue": "waf-<unique-value>.waf.prd.f5aas.com",
            "discovery": {
                "cloudProvider": "",
                "cloudRegion": "",
                "dnsProvider": "",
                "error": "NO_ERROR",
                "ipGeolocations": [],
                "isHTTP": false,
                "isHTTPS": false,
                "metadata": "",
                "recommendedWafRegion": ""
            },
            "fqdn": "app.example.com",
            "waf_regions": {
                "aws": {
                    "us-west-2": {
                        "endpoint": {
                            "dns_name": "dvwa.waf.dev.f5aas.com",
                            "http": {
                                "enabled": true,
                                "port": 8080
                            },
                            "https": {
                                "enabled": true,
                                "port": 4443
                            },
                            "ip_geolocation": {
                                "city": "san jose",
                                "continent": "North America",
                                "country": "united states",
                                "latitude": 37.24250030517578,
                                "longitude": -121.83499908447266,
                                "region": "california"
                            }
                        }
                    }
                }
            }
        },
        "waf_service": {
            "application": {
                "description": "Example Application",
                "fqdn": "app.example.com",
                "http": {
                    "enabled": true,
                    "port": 80
                },
                "https": {
                    "enabled": true,
                    "port": 443,
                    "tls": {
                        "certificate_id": "cert-aaQgtCI-Px"
                    }
                },
                "waf_regions": {
                    "aws": {
                        "us-west-2": {
                            "endpoint": {
                                "dns_name": "dvwa.waf.dev.f5aas.com",
                                "http": {
                                    "enabled": true,
                                    "port": 8080
                                },
                                "https": {
                                    "enabled": true,
                                    "port": 4443
                                }
                            }
                        }
                    }
                }
            },
            "industry": "finance",
            "policy": {
                "compliance_enforcement": {
                    "data_guard": {
                        "cc": true,
                        "enabled": true,
                        "ssn": true
                    },
                    "sensitive_parameters": {
                        "enabled": true,
                        "parameters": [
                            "password",
                            "creditcard"
                        ]
                    }
                },
                "encoding": "utf-8",
                "high_risk_attack_mitigation": {
                    "allowed_methods": {
                        "enabled": true,
                        "methods": [
                            {
                                "contains_http_data": true,
                                "name": "POST"
                            },
                            {
                                "contains_http_data": false,
                                "name": "HEAD"
                            },
                            {
                                "contains_http_data": false,
                                "name": "GET"
                            }
                        ]
                    },
                    "api_compliance_enforcement": {
                        "enabled": true
                    },
                    "disallowed_file_types": {
                        "enabled": true,
                        "file_types": [
                            "exe",
                            "com",
                            "bat",
                            "dll"
                        ]
                    },
                    "enabled": true,
                    "enforcement_mode": "blocking",
                    "geolocation_enforcement": {
                        "disallowed_country_codes": [
                            "AF",
                            "BY"
                        ],
                        "enabled": true
                    },
                    "http_compliance_enforcement": {
                        "enabled": true
                    },
                    "ip_enforcement": {
                        "enabled": true,
                        "ips": [
                            {
                                "action": "block",
                                "address": "1.2.3.4",
                                "description": "This is an app scanner",
                                "log": true
                            },
                            {
                                "action": "allow",
                                "address": "1.2.3.5",
                                "description": "some description",
                                "log": false
                            }
                        ]
                    },
                    "signature_enforcement": {
                        "enabled": true
                    },
                    "websocket_compliance_enforcement": {
                        "enabled": true
                    }
                },
                "malicious_ip_enforcement": {
                    "enabled": true,
                    "enforcement_mode": "blocking",
                    "ip_categories": [
                        {
                            "block": true,
                            "log": true,
                            "name": "tor_proxies"
                        },
                        {
                            "block": false,
                            "log": true,
                            "name": "cloud_services"
                        }
                    ]
                },
                "threat_campaigns": {
                    "campaigns": [
                        {
                            "enabled": false,
                            "id": "cmp177c3bc27c2545ce8571242f1b2022a4"
                        },
                        {
                            "enabled": true,
                            "id": "cmp177c3bc27c2545ce8571242f1b2022a5"
                        }
                    ],
                    "enabled": true,
                    "enforcement_mode": "blocking"
                }
            }
        }
    },
    "create_time": "2020-03-27T20:23:39.729955Z",
    "update_time": "2020-03-27T21:02:02.157258Z",
    "cancel_time": null,
    "end_time": null
}

Update the DNS records for your application with a new or updated CNAME record using the new CNAMEValue URL in the response. This will force requests directed to your main application domain to first go through Essential App Protect service. After you’ve updated DNS records, it can take up to 72 hours for it to fully propagate, but it’s typically much faster. You can validate that your CNAME has been resolved by testing your subscription with the following request and checking the cname_resolved value.

Postman: Test CNAME

POST https://{{HOSTNAME}}/{{API_VERSION}}/svc-subscription/subscriptions/{{SUBSCRIPTION_ID}}/test

– RESPONSE

{
    "configuration": {
        "cname_resolved": true
    }
}

Once your CNAME is resolved, your application is actively protected by Essential App Protect.

Add Essential App Protect IPs to Allow list

The last step is to ensure that all traffic reviewed and passing inspection in Essential App Protect can be successfully relayed to your application. To do this, you’ll need to add the deployment regions IP addresses used by Essential App Protect to the allow list for your application. Instructions for doing this can be found in the portal setup instructions. whitelist


Schema

This section covers the schema used for creating or modifying an Essential App Protect configuration. The purpose is to help with the use of the schema when working with the API programmatically. Details of each name/value pair in the schema are defined in the API reference guide Create Subscription, including the type (string, integer, Boolean, array, etc.) and a regular expression defining the correct syntax for the value, if applicable. To see the Essential App protect configuration of the schema, set the service_type to waf in the middle column, and set the Example field to waf in the right column.

The Essential App Protect schema is a JSON data structure that holds all of the information about a specific service instance. Below is an example of a schema showing only the top-level parameters.

{
    "account_id": "a-aaQgt6MlaD",
    "catalog_id": "c-aa9N0jgHI4",
    "service_type": "waf",
    "service_instance_name": "{{SERVICE_NAME}}",
    "configuration": {...}
}
  • account_id: When you created your account, Cloud Services assigned a unique account ID to your account. When you create new service instances (for any service), each instance is associated with your account by assigning your account ID to account_id.
  • catalog_id is the ID for the service type this data structure represents. For Essential App Protect, the catalog_id will always be c-aa9N0jgHI4.
  • service_type is the human readable version of catalog_id. For Essential App Protect, it will always be waf.
  • service_instance_name is the name you provide for this service instance. This is how you will see this service instance in the portal and distinguish it from other Essential App Protect service instances.
  • configuration defines all aspects of this service instance. The JSON below shows the first level contents if the configuration object.
"configuration": {
    "waf_service": {...},
    "update_comment: ""
}
  • waf_service holds all of the settings for this Essential App Protect service instance.
  • update_comment: Whenever you make a change to your Essential App Protect service instance (PUT method), you have the option to create an update comment describing what changed in this update. In the portal this comment will show in the Description column of the Service-specific Events table in the portal. For the API, see the App Configuration Service section.
"configuration": {
    "waf_service": {
        "application": {...},
        "industry": "finance",
        "policy": {...}
    }
}
  • application holds information about the application being protected by this instance of Essential App Protect. For more information, see the Application section.
  • industry: This is reserved for future use.
  • policy defines how the application will be protected. holds information about the application being protected by this instance of Essential App Protect. For more information, see the Application section.

Application

The application object holds all of the information about your application, including the domains and subdomains of the protected app, specifics for HTTP and HTTPS requests, the endpoint and region information, caching, and a description for reference.

 "configuration": {
     "waf_service": {
         "application": {
             "fqdn": "www.example.com",
             "http": {...},
             "https": {...},
             "waf_regions": {...},
             "description": "Example Application",
             "additional_fqdns": [
                 "app.example.com",
                 "store.example.com"
             ],
             "protected_uris": [],
             "unprotected_uris": [
                 "/images"
             ],
             "ntlm": false,
             "cache": {...}
         },
         "industry": "finance",
         "policy": {...}
     }
 }
  • fqdn, additional_fqdns specify the application and subdomains of the application you want to protect. If you have additional subdomains you would also like to protect with the same service instance, you can enter them in the additional_fqdns, but they must all be on the same domain.
  • description: An alternate description of the protected application.
  • protected_uris and unprotected_uris tell Essential App Protect which portions of your application should be protected or unprotected. By default, protected_uris is “/”, meaning the entire domain is protected. If you specify a subset of your application like “/images” to be unprotected, then all requests to that URI and below will simply be passed through to your application without any validation. Alternatively, you can specify “/” for unprotected URIs and then specify “/images” for protected URIs, and then only “/images” will be protected. In general, you can have overlap between protected and unprotected URIs as long as one is a subset of the other.
  • ntlm: Allows proxying requests with NTLM Authentication. The upstream connection is bound to the client connection once the client sends a request with the “Authorization” header field value starting with “Negotiate” or “NTLM”. Further client requests will be proxied through the same upstream connection, keeping the authentication context. The default is false.

HTTP/HTTPS

http, https specify how Essential App Protect will work with HTTP and HTTP requests going to your application.

"configuration": {
    "waf_service": {
        "application": {
            "fqdn": "www.example.com",
            "http": {
                "enabled": true,
                "https_redirect": true,
                "port": 80
            },
            "https": {
                "enabled": true,
                "port": 443,
                "tls": {
                    "certificate_id": "cert-aaQgtCI-Px",
                    "version": "1.2"
                }
            },
            "waf_regions": {...},
            "description": "Example Application",
            "additional_fqdns": [...],
            "protected_uris": [...],
            "unprotected_uris": [...],
            "ntlm": false,
            "cache": {...}
        },
        "industry": "finance",
        "policy": {...}
    }
}
  • enabled specifies whether or not the HTTP/HTTPS protocol is enabled (Boolean - true or false). If the protocol is enabled, then Essential App Protect will create a listener for that protocol. An application must have at least one protocol enabled.
  • https_redirect: If enabled, this parameter tells Essential App Protect to forward all incoming HTTP traffic to the application as an HTTPS request, thus encrypting the traffic. If https_redirect is enabled, then the https protocol must also be enabled, and the https protocol must have an SSL/TLS certificate specified. See Redirect HTTP traffic to HTTPS for an example.
  • port specifies the port for the protocol. HTTP commonly uses port 80, and HTTPS commonly uses port 443, but other port numbers can be used.
  • certificate_id holds the ID of the SSL/TLS certificate used for the HTTPS protocol. This ID is returned when you add the certificate to your account. See Add SSL/TLS Certificate for more information on adding a certificate to your account and getting the certificate ID.
  • version sets the minimum TLS version allowed for the HTTPS listener. Allowable minimum versions are 1.0, 1.1, and 1.2. The default and recommended version is 1.2, which tells Essential App Protect to only accept requests that use TLS 1.2. If you set version to a lower value, then Essential App Protect will accept requests that use that version or higher, for example, setting version to 1.1 will allow 1.1 and 1.2 requests. Note: Setting version to 1.0 is strongly discouraged because it leaves your app susceptible to a number of vulnerabilities.

Application regions

An application can have multiple endpoints to service requests. Essential App Protect will deploy to one or more regions to protect all application endpoints. You control how that is done in the waf_regions object highlighted below.

 "configuration": {
     "waf_service": {
         "application": {
             "fqdn": "www.example.com",
             "http": {...},
             "https": {...},
             "waf_regions": {
                 "aws": {
                     "us-west-2": {
                         "endpoint": {
                             "http": {
                                 "enabled": true,
                                 "port": 8080
                             },
                             "https": {
                                 "enabled": true,
                                 "port": 4443
                             },
                             "ips": [
                                 "173.236.xxx.xxx",
                                 "173.236.yyy.yyy"
                             ]
                         }
                     },
                     "eu-west-2" {...}
                 }
             },
             "description": "Example Application",
             "additional_fqdns": [...],
             "protected_uris": [...],
             "unprotected_uris": [...],
             "ntlm": false,
             "cache": {...}
         },
         "industry": "finance",
         "policy": {...}
     }
 }
  • waf_regions lists the cloud platforms that Essential App Protect can use for deployment. Currently Essential app protect supports Amazon Web Services (AWS).
  • aws lists the AWS regions you want to use for your application endpoints. You must have at least one.
    • http, https: Each region will specify HTTP and HTTPS settings for the endpoint(s) serviced by this region in a similar fashion to the application HTTP/HTTPS settings.
    • ips is an array that specifies one or more application endpoints to be serviced by this region. Generally you should choose the AWS region closest to your application endpoint(s) to minimize latency. For a list of supported regions, see Which AWS deployment regions are supported by Essential App Protect? in the FAQ.

Cache

The complete cache object is shown below with explanations following. When using the API (or optionally with the JSON Configuration tab in the portal), you will fill out the cache object with the appropriate values.

 "configuration": {
     "waf_service": {
         "application": {
             "fqdn": "www.example.com",
             "http": {...},
             "https": {...},
             "waf_regions": {...},
             "description": "Example Application",
             "additional_fqdns": [...],
             "protected_uris": [...],
             "unprotected_uris": [...],
             "ntlm": false,
             "cache": {
                 "enabled": true,
                 "provider": {
                     "cloudfront": {
                         "behaviors": {
                             "default": {
                                 "compression": true,
                                 "cookies": {
                                     "forward": "ALL",
                                     "forward_list": []
                                 },
                                 "headers": {
                                     "forward": "LIST",
                                     "forward_list": [
                                         "Authorization",
                                         "Accept",
                                         "User-Agent",
                                         "X-APP-TRUE"
                                     ]
                                 }
                             }
                         },
                         "edge_tier": "EDGE_TIER_3"
                     }
                 }
             }
         },
         "industry": "finance",
         "policy": {...}
     }
 }
  • enabled – true turns on caching using the settings in the cache object; false turns off caching.

  • provider – this object allows caching from different content delivery networks (CDNs). Currently, only CloudFront is available.

    • cloudfront – this object holds the settings for CloudFront integration. The contents of this object will be specific to CloudFront.

      • behaviors - A complex type that describes how CloudFront processes requests. For details, see the CloudFront documentation CacheBehavior.

        • default – applies to all application URIs. In the current release, default is the only option.
          • compression – Boolean to specify whether you want CloudFront to automatically compress certain files for this cache behavior. If so, specify true; if not, specify false. For more information, see Serving Compressed Files in the Amazon CloudFront Developer Guide. For specific the filetypes that are supported for compression, see the AWS compression file list.
          • cookies
            • forward
              • ALL – All cookies in viewer requests are included in the cache key and are automatically included in origin requests.
              • LIST - You specify which of the cookies in viewer requests are included in the cache key and automatically included in origin requests.
            • forward_list – A list of cookies specify cookies by their name, not their value. For example, if your cookie is Cookie: session_ID=abcd1234, then you specify the cookie as session_ID, not session_ID=abcd1234. You can have a maximum of 10 cookies in the list, and the list size cannot exceed 512 bytes minus the number of cookies in the list.
          • headers
            • forward
              • LIST - You specify which of the headers in viewer requests are included in the cache key and automatically included in origin requests.
              • forward_list – A list of headers you want to forward to the application. You can specify standard headers or your own custom headers. You can specify a maximum of 10 headers. For a list of headers you can forward, see the AWS HTTP Request Headers and CloudFront Behavior.
      • edge_tier – Edge tiers provide you an option to lower the prices you pay to deliver content out of Amazon CloudFront. By default, Amazon CloudFront minimizes end user latency by delivering content from its entire global network of edge locations. However, because they charge more where our costs are higher, this means that you pay more to deliver your content with low latency to end-users in some locations. Edge tiers let you reduce your delivery prices by excluding Amazon CloudFront’s more expensive edge locations from your Amazon CloudFront distribution. Edge tier values are shown in the table below. The preferred default would be Edge Tier 3, which will include all global edge locations.

        Edge
        Locations
        Included
        Within



        US &
        Canada





        Europe &
        Israel





        South
        Africa,
        Kenya, &
        Middle
        East


        South
        America





        Japan






        Australia






        Singapore,
        South
        Korea,
        Taiwan,
        Hong
        Kong, &
        Philippines
        India






        Edge Tier 3 Yes Yes Yes Yes Yes Yes Yes Yes
        Edge Tier 2 Yes Yes Yes Yes Yes Yes x x
        Edge Tier 1 Yes Yes x x x x x x

Cache Invalidation (Purging)

If you need to remove a file from CloudFront edge caches before it expires, you can invalidate the file from edge caches. The next time a viewer requests the file, CloudFront returns to the origin to fetch the latest version of the file.

You can work with the invalidations using the invalidations API. Below is a list of API requests. Substitute your service instance id for {{service_instance_id}}.

Get a list of CloudFront invalidations

GET https://api.cloudservices.f5.com/waf/v1/app/{service_instance_id}/cache/cloudfront/invalidations

– RESPONSE

{
    "invalidations": [
        {
            "invalidation_id": "I2SPDI3HT65CFL",
            "status": "InProgress",
            "date_time": "2020-10-13T16:07:43.463Z"
        },
        {
            "invalidation_id": "IBZP5T3XK81M5",
            "status": "Completed",
            "date_time": "2020-10-13T16:02:53.063Z"
        }
   ]
}

Create a new invalidation

To invalidate files, you can specify either the path for individual files or a path that ends with the * wildcard, which might apply to one file or to many, as shown in the following examples:

  • /images/image1.jpg
  • /images/image*
  • /images/*
POST https://api.cloudservices.f5.com/waf/v1/app/{service_instance_id}/cache/cloudfront/invalidations

– PAYLOAD

{
    "paths": [
        "/static/image.png",
        "/site/*"
    ]
}

– RESPONSE

{
    "invalidation_id": "I2SPDI3HT65CFL",
    "status": "InProgress",
    "paths": [
        "/static/image.png",
        "/site/*"
    ]
   "date_time": "2020-10-13T16:07:43.463Z"
}

Get an invalidation by ID

GET https://api.cloudservices.f5.com/waf/v1/app/{service_instance_id}/cache/cloudfront/invalidations/IBZP5T3XK81M5

– RESPONSE

{
    "invalidation_id": "IBZP5T3XK81M5",
    "status": "Completed",
     "paths": [
        "/static/image.png",
        "/site/*"
    ]
    "date_time": "2020-10-13T16:02:53.063Z"
}

Security Policy

The policy object defines the security policy for your application. The security policy is divided into different sections based on the type of threat they cover.

 "configuration": {
     "waf_service": {
         "application": {...},
         "industry": "finance",
         "policy": {
             "encoding": "utf-8",
             "compliance_enforcement": {...},
             "high_risk_attack_mitigation": {...},
             "malicious_ip_enforcement": {...},
             "threat_campaigns": {...}
        }
     }
 }
  • encoding tells Essential App Protect which type of characters are used for your application. If you’re not sure, 95% of all websites use UTF-8.
  • compliance_enforcement, high_risk_attack_mitigation, malicious_ip_enforcement, threat_campaigns: These objects allow you to tailor each portion of the security policy to suit your specific needs.

Compliance Enforcement

compliance_enforcement controls two features: data guard and sensitive parameters.

 "configuration": {
     "waf_service": {
         "application": {...},
         "industry": "finance",
         "policy": {
             "encoding": "utf-8",
             "compliance_enforcement": {
                 "data_guard": {
                     "enabled": true,
                     "cc": true,
                     "ssn": true
                 },
                 "sensitive_parameters": {
                     "enabled": true,
                     "parameters": [
                         "password",
                         "creditcard"
                     ]
                 }
             },
             "high_risk_attack_mitigation": {...},
             "malicious_ip_enforcement": {...},
             "threat_campaigns": {...}
        }
     }
 }
  • data_guard is a feature that will mask sensitive user information, also known as response scrubbing, so the values are obscured from all downstream views or logs.
    • enabled turns the entire feature on or off. It is a Boolean with a value of either true or false.
    • cc enables credit card masking. If both enabled and cc are enabled, then credit card information is masked with asterisks.
    • ssn enables credit card masking. If both enabled and ssn are enabled, then credit social security numbers are masked with asterisks.
  • sensitive_parameters is a feature that will mask the contents of all parameters in the parameters list from any display or logging that is performed as part of the service. Unlike Data Guard, the sensitive parameters feature will not change the parameter value that is passed between the application server and web server.
    • enabled turns the entire feature on or off. It is a Boolean with a value of either true or false.
    • parameters is an array of strings of arbitrary length. Each string is a parameter whose contents will be masked if the enabled flag is set to true.

High Risk Attack Mitigation

High-Risk Attack Mitigation is an automatic attack mitigation feature that will evaluate each incoming request and calculate the likelihood that it is an incoming attack based on the type of violations that the specific request will trigger, and then it will allow immediate request blocking.

The high_risk_attack_mitigation object allows you to tailor this portion of the security policy to suit your specific needs.

 "configuration": {
     "waf_service": {
         "application": {...},
         "industry": "finance",
         "policy": {
             "encoding": "utf-8",
             "compliance_enforcement": {...},
             "high_risk_attack_mitigation": {
                 "enabled": true,
                 "enforcement_mode": "blocking",
                 "signature_enforcement": {...},
                 "allowed_methods": {...},
                 "disallowed_file_types": {...},
                 "api_compliance_enforcement": {...},
                 "http_compliance_enforcement": {...},
                 "websocket_compliance_enforcement": {...},
                 "geolocation_enforcement": {...},
                 "ip_enforcement": {...},
                 "exceptions": {...}
             },
             "malicious_ip_enforcement": {...},
             "threat_campaigns": {...}
        }
     }
 }
  • enabled turns on or off the entire High-Risk Attack Mitigation feature. It is a Boolean with a value of either true or false.

  • enforcement_mode: High-Risk Attack Mitigation can be enforced in two ways: blocking or monitoring. blocking means requests that violate High-Risk Attack Mitigation policy will not be passed through to your application. monitoring means requests that violate High-Risk Attack Mitigation policy will be passed through to your application, but they will be logged as suspicious for future review.

  • signature_enforcement: Attack signatures are rules or patterns that identify attacks or classes of attacks on a web application and its components. The signature enforcement feature compares patterns in the attack signatures against the contents of requests and responses looking for potential attacks. Some of the signatures are designed to protect specific operating systems, web servers, databases, frameworks or applications. For more details, see the Attack Types and Attack Signatures sections in the Security Details document.

    • enabled is a Boolean flag (true or false) that turns on or off signature enforcement.
     "high_risk_attack_mitigation": {
         "enabled": true,
         "enforcement_mode": "blocking",
         "signature_enforcement": {
             "enabled": true
         },
         "allowed_methods": {...},
         "disallowed_file_types": {...},
         "api_compliance_enforcement": {...},
         "http_compliance_enforcement": {...},
         "websocket_compliance_enforcement": {...},
         "geolocation_enforcement": {...},
         "ip_enforcement": {...},
         "exceptions": {...}
     }
    
  • allowed_methods governs the use of specific HTTP request methods. By default, Essential App Protect allows POST, HEAD, and GET methods.

    • enabled is a Boolean flag (true or false) that turns on or off allowed methods enforcement.
    • methods is the array of methods that are allowed. Within each method, name is the HTTP method being allowed, and contains_http_data is a Boolean indicating whether or not the request includes a message body or payload. The default is dependent on the method: for example, GET and HEAD default to false and POST and PUT default to true.
     "high_risk_attack_mitigation": {
         "enabled": true,
         "enforcement_mode": "blocking",
         "signature_enforcement": {...},
         "allowed_methods": {
             "enabled": true,
             "methods": [
                 {
                     "name": "POST",
                     "contains_http_data": true
                 },
                 {
                     "name": "HEAD",
                     "contains_http_data": false
                 },
                 {
                     "name": "GET",
                     "contains_http_data": false
                 }
             ]
         },
         "disallowed_file_types": {...},
         "api_compliance_enforcement": {...},
         "http_compliance_enforcement": {...},
         "websocket_compliance_enforcement": {...},
         "geolocation_enforcement": {...},
         "ip_enforcement": {...},
         "exceptions": {...}
     }
    
  • disallowed_file_types allows you to specify the file types that are disallowed in traffic to the web application being protected. Adding disallowed file types is useful for file types that you know should never appear on your site (such as .exe files).

    • enabled is a Boolean flag (true or false) that turns on or off allowed methods enforcement.
    • file_types is an arbitrary length array of strings holding the extensions of file types you do not want accessed.
     "high_risk_attack_mitigation": {
         "enabled": true,
         "enforcement_mode": "blocking",
         "signature_enforcement": {...},
         "allowed_methods": {...},
         "disallowed_file_types": {
             "enabled": true,
             "file_types": [
                 "exe",
                 "com",
                 "bat",
                 "dll"
             ]
         },
         "api_compliance_enforcement": {...},
         "http_compliance_enforcement": {...},
         "websocket_compliance_enforcement": {...},
         "geolocation_enforcement": {...},
         "ip_enforcement": {...},
         "exceptions": {...}
     }
    
  • api_compliance_enforcement enforces proper XML requests by setting the enabled flag to true. The system checks that the request contains XML data that is well-formed, according to W3C standards. Sending a document which the application was not expecting to handle can result in various attacks, like denial of service.

  • http_compliance_enforcement verifies the HTTP request is properly formed when the enabled flag is set to true. Malformed HTTP requests can be used to bypass proxy filters, poison caches, or cause the response from one request to be incorrectly matched with another; Ref: OWASP HTTP.

  • websocket_compliance_enforcement protects WebSocket connections from exploits related to the WebSocket protocol by setting the enabled flag to true. WebSocket connections are used for bi-directional, real-time applications such as support chats, news feeds, immediate quotes, or collaborative work. It is important to secure the content that is exchanged, otherwise an attacker could potentially gain access to the application server.

     "high_risk_attack_mitigation": {
         "enabled": true,
         "enforcement_mode": "blocking",
         "signature_enforcement": {...},
         "allowed_methods": {...},
         "disallowed_file_types": {...},
         "api_compliance_enforcement": {
             "enabled": true
         },
         "http_compliance_enforcement": {
             "enabled": true
         },
         "websocket_compliance_enforcement": {
             "enabled": true
         },
         "geolocation_enforcement": {...},
         "ip_enforcement": {...},
         "exceptions": {...}
     }
    
  • geolocation_enforcement gives you the ability to deny requests from a list of countries you specify.

    • enabled is a Boolean flag (true or false) that turns on or off geolocation enforcement.
    • disallowed_country_codes is an arbitrary length array of strings holding the country codes that will be blocked. For a list of country codes, see countrycode.org.
     "high_risk_attack_mitigation": {
         "enabled": true,
         "enforcement_mode": "blocking",
         "signature_enforcement": {...},
         "allowed_methods": {...},
         "disallowed_file_types": {...},
         "api_compliance_enforcement": {...},
         "http_compliance_enforcement": {...},
         "websocket_compliance_enforcement": {...},
         "geolocation_enforcement": {
             "enabled": true,
             "disallowed_country_codes": [
                 "BY",
                 "CU"
             ]
         },
         "ip_enforcement": {...},
         "exceptions": {...}
     }
    
  • ip_enforcement gives you the ability to allow or deny requests from specific IP addresses.

    • enabled is a Boolean flag (true or false) that turns on or off IP enforcement.
    • ips is an arbitrary length array of strings holding a list of IP addresses and enforcement parameters.
      • address: the IP address to be enforced.
      • description: a human readable description for the purpose of the enforcement for this IP address.
      • action: allow means all requests from this IP address will be allowed, and block means all requests from this IP address will be blocked. Ignore Malicious IP means that you want to allow requests from this IP, even though it might be labeled malicious, but you still want to block attacks that might come from this IP.
      • log: is a Boolean flag (true or false) that turns on or off event logging for this IP address.
     "high_risk_attack_mitigation": {
         "enabled": true,
         "enforcement_mode": "blocking",
         "signature_enforcement": {...},
         "allowed_methods": {...},
         "disallowed_file_types": {...},
         "api_compliance_enforcement": {...},
         "http_compliance_enforcement": {...},
         "websocket_compliance_enforcement": {...},
         "geolocation_enforcement": {...},
         "ip_enforcement": {
             "enabled": true,
             "ips": [
                 {
                     "address": "173.236.xxx.xxx",
                     "description": "Bad actor",
                     "action": "block",
                     "log": true
                 },
                 {
                     "address": "173.236.yyy.yyy",
                     "description": "Good actor",
                     "action": "allow",
                     "log": false
                 }
             ]
         },
         "exceptions": {...}
     }
    

Exceptions

When Essential App Protect sees suspicious content in requests to your application, it evaluates the probability that the request is an attack. If the probability is high enough, the request is blocked to keep your app safe. Sometimes, however, valid requests can appear to be an attack–often called false positives. Exceptions are a way for you to tell Essential App Protect to allow (not block) requests with specific features.

  • exceptions give you the ability to disable specific protection features for cases where you know the request is valid. There are a number of types of exceptions available as shown below.

     "high_risk_attack_mitigation": {
         "enabled": true,
         "enforcement_mode": "blocking",
         "signature_enforcement": {...},
         "allowed_methods": {...},
         "disallowed_file_types": {...},
         "api_compliance_enforcement": {...},
         "http_compliance_enforcement": {...},
         "websocket_compliance_enforcement": {...},
         "geolocation_enforcement": {...},
         "ip_enforcement": {...},
         "exceptions": {
             "url_objects": {...},
             "parameters_objects": {...},
             "headers": [...],
             "cookies": [...],
             "evasions": [...],
             "http_compliance": [...],
             "attack_signatures": [...]
         }
     }
    
  • url_objects: this class of exceptions is for false positives on a specific URI and either a specific attack signature or specific meta characters used.

    • meta_characters: array of the meta character(s) you want to allow (ASCII format). These characters (if any) must be present in the URI for the normally blocked request to be allowed.
    • url_names: array of URIs paired with associated signature ids.
      • signature_ids: array of attack signature IDs. The request will be allowed for these attack signatures but no others.
      • uri: the endpoint for the request (base 64 encoded). For example, the value of uri for this request, GET http://www.example.com/dir/page.html?param=true, would be “ZGlyL3BhZ2UuaHRtbA==” (“dir/page.html” converted to base 64).

    Example: this request comes in: GET http://www.example.com/onScroll%3d%20onScroll%20//onScroll/%3d%20onScroll%20//onScroll%3d%20onScroll%20?p=&p=&q= and is blocked based on attack signature 200001278 and meta character “=”. The following exception means that any request using the endpoint “onscroll” (base 64 “b25zY3JvbGw=”) and the meta character “=” (ASCII 61) that would normally be blocked with attack signature 200001278 will now be allowed.

    "exceptions": {
        "url_objects": {
            "meta_characters": [
                61
            ],
            "url_names": [
                {
                    "signature_ids": [
                        "200001278"
                    ],
                    "uri": "b25zY3JvbGw="
                }
            ]
        },
        "parameters_objects": {...},
        "headers": [...],
        "cookies": [...],
        "evasions": [...],
        "http_compliance": [...],
        "attack_signatures": [...]
    }
    
  • parameters_objects: this class of exceptions is for false positives on a specific set of URL parameters and either a specific attack signature or specific meta characters used.

    • meta_characters_param_name: array of meta characters allowed in the URL parameter names (ASCII format).
    • parameter_names: array of parameter names paired with signature IDs and meta characters.
      • name: the parameter name you want to allow (base 64 encoded)
      • signature_ids: array of attack signature ids associated with the meta characters.
      • param_value_meta_characters: array of meta characters allowed in the URL parameter values (ASCII format).

    Example: this request comes in: GET http://www.example.com/parts.php?partnum=ab457<superscript> and is blocked based on attack signature 200001475 and meta characters “<” and “>”. The following exception means that any request using the parameter “partnum” (base 64 “cGFydG51bQ==”), the meta characters “<” and “>” (ASCII 60 and 62) that would normally be blocked with attack signature 200001475 will now be allowed. The expected allowable requests will not have meta characters in the parameter name “partnum”, so the meta_characters_param_name array is blank (the object could be left out completely). If on the other hand the parameter includes a metacharacter deemed illegal, like part$num, then meta_characters_param_name would include the ASCII value of $ (36).

    "exceptions": {
        "url_objects": {...},
        "parameters_objects": {
            "meta_characters_param_name": [
            ],
            "parameter_names": [
                {
                    "name": "cGFydG51bQ==",
                    "param_value_meta_characters": [
                        60,
                        62
                    ],
                    "signature_ids": [
                        "200001475"
                    ]
                }
            ]
        },
        "headers": [...],
        "cookies": [...],
        "evasions": [...],
        "http_compliance": [...],
        "attack_signatures": [...]
    }
    
  • headers is an array of specific headers and attack signatures that you want to allow.

    • name: the header name you want to allow for specific attack signature(s).
    • signature_ids: the list of specific attack signature(s) you want to allow for the header listed above.

    Example: this request comes in: GET http://www.example.com with the header X-Forwarded-Host: <script src="http://<?php echo _SERVER['HOST'] ?>/script.js"> and is blocked based on attack signatures 200000097, 200001140, and 200004124. The following exception means that any request using the header “X-Forwarded-Host” (base 64 “WC1Gb3J3YXJkZWQtSG9zdA==”) that would normally be blocked with the listed attack signatures will now be allowed.

    "exceptions": {
        "url_objects": {...},
        "parameters_objects": {...},
        "headers": [
            {
                "name": "WC1Gb3J3YXJkZWQtSG9zdA==",
                "signature_ids": [
                    "200000097",
                    "200001140",
                    "200004124"
                ]
            }
        ],
        "cookies": [...],
        "evasions": [...],
        "http_compliance": [...],
        "attack_signatures": [...]
    }
    
  • cookies is an array of specific cookies and attack signatures that you want to allow.

    • name: the cookie name you want to allow for specific attack signature(s).
    • signature_ids: the list of specific attack signature(s) you want to allow for the cookie listed above.

    Example: this request comes in: GET http://www.example.com with the cookie MyCookie=fhfh^%26$$<script> and is blocked based on attack signatures 200001475, and 200000098. The following exception means that any request using a cookie named “MyCookie” (base 64 “TXlDb29raWU=”) that would normally be blocked with the listed attack signatures will now be allowed.

    "exceptions": {
        "url_objects": {...},
        "parameters_objects": {...},
        "headers": [...],
        "headers": [...],
        "cookies": [
            {
                "name": "TXlDb29raWU=",
                "signature_ids": [
                    "200001475",
                    "200000098"
                ]
        ],
        "evasions": [...],
        "http_compliance": [...],
        "attack_signatures": [...]
    }
    
  • evasions are triggered when Essential App Protect fails to normalize requests. Normalization is the process of decoding requests that are encoded. The system needs to perform normalization because some applications send requests that contain different types of encoded escapes that Essential App Protect needs to interpret before doing any further processing.

    If Essential App Protect receives a request that is URL-encoded, certain characters may be replaced with a percent sign (%) followed by numbers. For example, the URL http://www.mystore.com/big sales.html is changed to http://www.mystore.com/big%20sales.html. In this example, the space is replaced with %20. Even though the %20 is a legitimate request, Essential App Protect needs to decode the request because hackers use these techniques to send crafted requests that bypass the attack signatures and expose the application to different attacks.

    "exceptions": {
        "url_objects": {...},
        "parameters_objects": {...},
        "headers": [...],
        "headers": [...],
        "cookies": [...],
        "evasions": [
            "%u decoding"
        ],
        "http_compliance": [...],
        "attack_signatures": [...]
    }
    
  • http_compliance is comprised of a list of individual sub violations which perform HTTP validation checks. If a violation is triggered due to a match of one or more of the HTTP Protocol Compliance sub-options, the HTTP Protocol Compliance option which failed along with the name of the sub violation will be listed in the reported security incident event.

    The HTTP Protocol Compliance options consists of the following validation checks.

    Name Description
    POST request with Content-Length: 0 The system examines the POST request for the Content-Length header. If the header is missing or the value of the header is 0, the system will report the POST as a violation.
    Header name with no header value The system examines the request for header names that do not contain a value. If a header is found without a corresponding value, a violation is issued.
    Several Content-Length headers The system examines the request for multiple Content-Length headers. If more than one Content-Length header is found, the system will report the violation.
    Chunked request with Content-Length header The system examines the request for Transfer-Encoding and Content-Length headers. If both exist and the value of the Transfer-Encoding header is chunked, the system logs the violation.
    Body in GET or HEAD requests The system examines requests that use the HEAD or GET method to see if the request contains data within the body of the request. This is illegal as GET and HEAD requests are requesting information and are not used to send data. If data is found in either method, a violation is issued.
    Bad multipart/form-data request parsing When the content type of a request header contains the Multipart/form-data substring, the system checks whether each multipart request chunk contains a Content-Disposition header containing a name value and corresponding parameter key value. For example: name=”parameter_key”. If the Content-Disposition header does not contain the required parameters, a violation is issued.
    Bad multipart parameters parsing

    The system examines the requests to verify that the Content-Disposition header matches the format: name=”param_key”;rn. The system also checks that the following is true:

    • A boundary follows immediately after the request headers.
    • The parameter value matches the format: ‘name=”param_key”;rn.
    • A chunked body contains at least one CRLF.
    • A chunked body ends with CRLF.
    No Host header in HTTP/1.1 request The system examines requests sent by a client using the HTTP version 1.1 protocol to see if it contains a Host header. This is required per RFC 2616 - Hypertext Transfer Protocol – HTTP/1.1. If no Host header is present, a violation is issued.
    CRLF characters before request start The system examines a request to see if the request begins with the characters CRLF. This is not allowed; if a CRLF is found at the beginning of a request, a violation is issued.
    Host header contains IP address The system examines the Host header of a client’s request to verify that the Host header value is not an IP address. If an IP address is found within the Host header, a violation issued.
    Content length should be a positive number he system examines the value of the Content-Length header to verify the value is greater than zero. If the value is not greater than or equal to zero, or a value other than an integer, a violation is issued.
    Bad HTTP version The system examines the requests to verify whether the client requests are using HTTP protocol version 1.0 or higher.
    Null in request The system examines the request for the presence of any NULL character (except for a NULL in the binary part of a multipart request); if found, a violation is issued.
    High ASCII characters in headers The system inspects request headers for ASCII characters greater than 127, which are not permitted. If an ASCII value greater than 127 is found, a violation is issued.
    Unparseable request content The system examines requests for content that cannot be parsed. When unparseable content is encountered, a violation is issued.
    Check maximum number of headers: maximum <number> headers The system compares the number of headers in the request against the maximum number specified in this option. If the number of headers in the request exceeds the maximum number allowed in this option, a violation is issued. Default setting maximum of 20 headers.
    Bad host header value Starting in BIG-IP ASM 11.0.0. When enabled, this option specifies that the system inspects requests to see whether they contain a non-RFC compliant header value.
    Check maximum number of parameters: maximum Starting BIG-IP ASM 11.2.0. When enabled, this option specifies that the system compares the number of parameters in the request against the maximum number you specify here. A request that contains more parameters than allowed by the security policy should be considered a possible attack on the server. Type a number in the box to specify how many parameters are allowed. The default value is set to a maximum of 500 parameters.
    Multiple host headers Starting in BIG-IP ASM 11.5.0. Specifies, when checked (enabled), that the system examines requests to ensure that they contain only a single “Host” header.
    "exceptions": {
        "url_objects": {...},
        "parameters_objects": {...},
        "headers": [...],
        "headers": [...],
        "cookies": [...],
        "evasions": [...],
        "http_compliance": [
            "Header name with no header value"
        ],
        "attack_signatures": [...]
    }
    
  • attack_signatures is an array that allows you to disable one or more specific attack signatures. For a specific example, see Globally Disable an Attack Signature.

    • id is the attack signature ID that you don’t want to block.
    • enabled is a Boolean flag (true or false) that turns on or off blocking for the listed attack signature id.
    "exceptions": {
        "url_objects": {...},
        "parameters_objects": {...},
        "headers": {...},
        "cookies": {...},
        "evasions": {...},
        "http_compliance": {...},
        "attack_signatures": [
           {
              "id": "200010038",
               "enabled": false
           }
        ]
    }
    

Malicious IP Enforcement

A malicious IP is an IP address or security category associated with malicious activity. IP addresses gain a questionable reputation and are added to the database as a result of having performed exploits or attacks, or these addresses might represent proxy servers, scanners, or systems that have been infected.

  • malicious_ip_enforcement: This object allows you to tailor this portion of the security policy to suit your specific needs.
 "configuration": {
     "waf_service": {
         "application": {...},
         "industry": "finance",
         "policy": {
             "encoding": "utf-8",
             "compliance_enforcement": {...},
             "high_risk_attack_mitigation": {...},
             "malicious_ip_enforcement": {
                 "enabled": true,
                 "enforcement_mode": "blocking",
                 "ip_categories": [
                     {
                         "name": "tor_proxies",
                         "block": true,
                         "log": true
                     },
                     {
                         "name": "cloud_services",
                         "block": false,
                         "log": true
                     }
                     ...
                 ]
             },
             "threat_campaigns": {...}
        }
     }
 }
  • enabled turns on or off the entire Malicious IP Enforcement feature. It is a Boolean with a value of either true or false.

  • enforcement_mode: Malicious IP Enforcement can be enforced in two ways: blocking or monitoring. blocking means requests that violate Malicious IP Enforcement policy will not be passed through to your application. monitoring means requests that violate Malicious IP Enforcement policy will be passed through to your application, but they will be logged as suspicious for future review.

  • ip_categories is a fixed length array of malicious IP categories that you can control individually. The list of malicious IP categories is shown below.

    • name is the Malicious IP category that the following flags will affect.
    • block is a Boolean (true or false) that turns on or off the blocking of this category.
    • log is a Boolean (true or false) that turns on or off the logging of this category to the security events list. Note that if log is turned off, then block is turned off internally.
    Malicious IP category Description
    anonymous_proxies IP addresses that are associated with web proxies that shield the originator’s IP address (such as proxy and anonymization services).
    bot_nets IP addresses of computers that are infected with malicious software (Botnet Command and Control channels, and infected zombie machines) and are controlled as a group by a Bot master, and are now part of a botnet. Hackers can exploit botnets to send spam messages, launch various attacks, or cause target systems to behave in other unpredictable ways.
    cloud_services IP addresses and networks that belong to cloud providers, which offer services hosted on their servers via the Internet.
    denial_of_service IP addresses that have launched denial-of-service (DoS) attacks, distributed denial-of-service (DDoS) attacks, anomalous SYN flood attacks, or anomalous traffic detection. These attacks are usually requests for legitimate services, but occur at such a fast rate that targeted systems cannot respond quickly enough and become bogged down or unable to service legitimate clients.
    infected_sources Active IP addresses that issue HTTP requests with a low reputation index score, or that are known malicious web sites offering or distributing malware, shell code, rootkits, worms, or viruses.
    mobile_threats IP addresses of malicious and unwanted mobile applications.
    phishing_proxies IP addresses that host phishing sites, and other kinds of fraud activities, such as ad click fraud or gaming fraud.
    scanners IP addresses that are involved in reconnaissance, such as probes, host scan, domain scan, and password brute force, typically to identify vulnerabilities for later exploits.
    spam_sources IP addresses tunneling spam messages through proxy, anomalous SMTP activities and forum spam activities.
    tor_proxies IP addresses acting as exit nodes for the Tor Network. Exit nodes are the last point along the proxy chain and make a direct connection to the originator’s intended destination.
    web_attacks IP addresses involved in cross site scripting, iFrame injection, SQL injection, cross domain injection, or domain password brute force.
    windows_exploits Active IP addresses that have exercised various exploits against Windows resources by offering or distributing malware, shell code, rootkits, worms, or viruses using browsers, programs, downloaded files, scripts, or operating system vulnerabilities.

Threat Campaigns

Attackers are constantly looking for ways to exploit the latest vulnerabilities and/or new ways to exploit old vulnerabilities. F5’s Threat Research team is constantly monitoring malicious activity around the globe and creating signatures specific to these exploits. These Threat Campaign signatures are based on current “in-the-wild” attacks. Threat Campaign signatures contain contextual information about the nature and purpose of the attack.

As an example, a normal WAF signature might tell you that SQL injection was attempted. A Threat Campaign signature will tell you that a known threat actor used a specific exploit of the latest Apache Struts vulnerability in an attempt to deploy ransomware for cryptomining software.

  • threat_campaigns: this object allows you to tailor this portion of the security policy to suit your specific needs.
 "configuration": {
     "waf_service": {
         "application": {...},
         "industry": "finance",
         "policy": {
             "encoding": "utf-8",
             "compliance_enforcement": {...},
             "high_risk_attack_mitigation": {...},
             "high_risk_attack_mitigation": {...},
             "malicious_ip_enforcement": {...},
             "threat_campaigns": {
                 "enabled": true,
                 "enforcement_mode": "blocking",
                 "campaigns": [
                     {
                         "id": "cmp177c3bc27c2545ce8571242f1b2022a4",
                         "enabled": false
                     }
                 ]
             }
         }
     }
 }
  • enabled turns on or off the entire Threat Campaigns feature. It is a Boolean with a value of either true or false.
  • enforcement_mode: Threat Campaigns can be enforced in two ways: blocking or monitoring. blocking means requests that violate Threat Campaigns policy will not be passed through to your application. monitoring means requests that violate Threat Campaigns policy will be passed through to your application, but they will be logged as suspicious for future review.
  • campaigns is an array of the threat campaigns that you can control individually. The list of threat campaigns is maintained by F5 labs and is updated weekly or even more often. For more information on getting the list of threat campaigns and their associated campaign IDs, see Threat Campaigns Service.
    • id is the ID of the threat campaign you want to enable or disable.
    • enabled is a Boolean (true or false) that turns on or off the threat campaign specified in id.

Analytics Service

Security Events

The security events request allows you to get all security events for a specified time period, or to get details on a specific event.

  • subscription_id: this is required for authentication.
  • service_instance_id: this is required to specify the Essential App Protect service instance from which you are retrieving security events.
  • since: This specifies the beginning time interval (un UTC format) to query Security Events data. If not specified, then it will default to the until value minus 2 days.
  • until: this specifies the end interval to query Security Events data. If not specified, then it will default to the current date and time.
  • support_id: Specifying a support_id will return only the specified security event. Do not specify since or until.

Postman: Get Security Events and Get Security Events by ID

POST https://api.cloudservices.f5.com/waf/v1/analytics/security/events

– PAYLOAD

{
    "since": "2020-06-13T03:16:41Z",
    "until": "2020-06-13T03:16:41Z",
    "service_instance_id": "string",
    "support_id": "string",
    "subscription_id": "string"
}

– RESPONSE

{
    "total_size": 8,
    "events": [
        {
            "date_time": "2020-06-16T17:35:11Z",
            "geo_latitude": 33.6015,
            "geo_longitude": -117.712,
            "geo_country": "united states",
            "detection_events": [
                "Illegal meta character in value",
                "Attack signature detected",
                "Violation Rating Threat detected"
            ],
            "support_id": "5ac9c96c0b1228cfb8ed94cbb847f8c609324921713350776253",
            "response_code": "",
            "source_ip": "68.4.xxx.xxx",
            "method": "GET",
            "protocol": "HTTP",
            "query_string": "part-num=ab457%3Csuperscript%3E",
            "sig_ids": [
                "200001475"
            ],
            "sig_names": [
                "XSS script tag end (Parameter) (2)"
            ],
            "attack_types": [
                "Non-browser Client",
                "Abuse of Functionality",
                "Cross Site Scripting (XSS)"
            ],
            "ip_address_intelligence": "",
            "src_port": "51161",
            "sub_violations": [
                ""
            ],
            "uri": "/parts.php",
            "request": "GET /parts.php?part-num=ab457%3Csuperscript%3E HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: keep-alive\\r\\nUpgrade-Insecure-Requests: 1\\r\\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36\\r\\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\\r\\nAccept-Encoding: gzip, deflate\\r\\nAccept-Language: en-US,en;q=0.9\\r\\n",
            "violation_details": "[{\n\t\"type\": \"ATTACK_SIGNATURE\",\n\t\"details\": {\n\t\t\"context\": {\n\t\t\t\"type\": \"parameter\",\n\t\t\t\"param_name\": \"cGFydC1udW0=\",\n\t\t\t\"param_value\": \"YWI0NTc8c3VwZXJzY3JpcHQ+\"\n\t\t},\n\t\t\"signature\": [\n\t\t\t{\n\t\t\t\t\"id\": \"200001475\",\n\t\t\t\t\"buffer\": \"cGFydC1udW09YWI0NTc8c3VwZXJzY3JpcHQ+\",\n\t\t\t\t\"offset\": 20,\n\t\t\t\t\"length\": 7\n\t\t\t}\n\t\t]\n\t}\n},\n{\n\t\"type\": \"PARAMETER_VALUE_METACHAR\",\n\t\"details\": {\n\t\t\"context\": {\n\t\t\t\"type\": \"value\",\n\t\t\t\"param_name\": \"cGFydC1udW0=\",\n\t\t\t\"param_value\": \"YWI0NTc8c3VwZXJzY3JpcHQ+\"\n\t\t},\n\t\t\"meta_characters\": [\n\t\t\t{\n\t\t\t\t\"char\": \"PA==\",\n\t\t\t\t\"index\": 60,\n\t\t\t\t\"buffer\": \"YWI0NTc8c3VwZXJzY3JpcHQ+\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"char\": \"Pg==\",\n\t\t\t\t\"index\": 62,\n\t\t\t\t\"buffer\": \"YWI0NTc8c3VwZXJzY3JpcHQ+\"\n\t\t\t}\n\t\t]\n\t}\n}]",
            "header": "",
            "violation_rating": "4",
            "threat_campaign_names": "",
            "fragment": "",
            "request_status": "Blocked",
            "severity": "Critical",
            "category": [
                "HIGH_RISK_ATTACK"
            ],
            "geo_country_code": "US",
            "geo_state": "california",
            "geo_city": "laguna beach",
            "cloud_provider": "aws",
            "region": "us-west-2",
            "cell_id": "c2",
            "threat_campaign_ids": "",
            "violation_details_json": [
                {
                    "details": {
                        "context": {
                            "param_name": "cGFydC1udW0=",
                            "param_value": "YWI0NTc8c3VwZXJzY3JpcHQ+",
                            "type": "parameter"
                        },
                        "signature": [
                            {
                                "buffer": "cGFydC1udW09YWI0NTc8c3VwZXJzY3JpcHQ+",
                                "id": "200001475",
                                "length": 7,
                                "offset": 20
                            }
                        ]
                    },
                    "type": "ATTACK_SIGNATURE"
                },
                {
                    "details": {
                        "context": {
                            "param_name": "cGFydC1udW0=",
                            "param_value": "YWI0NTc8c3VwZXJzY3JpcHQ+",
                            "type": "value"
                        },
                        "meta_characters": [
                            {
                                "buffer": "YWI0NTc8c3VwZXJzY3JpcHQ+",
                                "char": "PA==",
                                "index": 60
                            },
                            {
                                "buffer": "YWI0NTc8c3VwZXJzY3JpcHQ+",
                                "char": "Pg==",
                                "index": 62
                            }
                        ]
                    },
                    "type": "PARAMETER_VALUE_METACHAR"
                }
            ]
        },
        ...
   ]
}

Statistics

The statistics request provides a numeric/time view of the malicious requests coming into your application. The response contains two primary objects: requests and histograms.

  • requests provides a view of the most recent five-minute period of activity.
    • since and until specify the time interval. Note that this time is based on the statistics request time and is not rounded to the nearest multiple of five minutes, zero seconds.
    • count shows the total number of malicious requests received during the period.
    • status shows the number of requests that were blocked and not_blocked.
    • previous_count shows how many malicious requests were in the previous five-minute period. This makes it easy to see if the malicious activity is increasing or decreasing in the current period.
  • histograms shows how many malicious requests were in each of the 25 most recent five-minute time periods. Each time period starts at a time rounded to the nearest multiple of 5 minutes, zero seconds, except the most recent period which will be from the start of the time period to the current time.

Postman: Get Security Statistics

POST https://api.cloudservices.f5.com/waf/v1/analytics/security/statistics

– PAYLOAD

{
    "service_instance_id": "waf-aagoB-gtVq",
    "subscription_id": "s-aawgtryfof"
}

– RESPONSE

{
    "requests": {
        "since": "2020-06-17T20:29:04Z",
        "until": "2020-06-17T20:34:04Z",
        "count": 5,
        "malicious": {
            "count": 5,
            "status": {
                "blocked": 5,
                "not_blocked": 0
            },
            "previous_count": 5
        }
    },
    "histograms": {
        "malicious": [
            {
                "date_time": "2020-06-17T18:30:00Z",
                "count": 8
            },
            {
                "date_time": "2020-06-17T18:35:00Z",
                "count": 2
            },
            ...
            {
                "date_time": "2020-06-17T20:30:00Z",
                "count": 4
            }
        ]
    }
}

App Configuration Service

Every time someone makes a change to the configuration of your service instance, Essential App Protect creates a new configuration state and stores it in a list. Changes can be made through the API, the portal, or a combination of both. The App Configuration Service allows you to access that list so that you can see what changes were made, when they were made, and the ability to roll back to a previous configuration. If you use the update_comment in the schema when you make configuration changes, you can label specific configurations, whether you’ve made any changes or not. This gives you the ability to do things like label known good states for easy roll-back, or you could label two different configurations allowing you to quickly and easily switch between those configurations.

List Configurations

This request returns a list of all configuration changes. The request will include the following variables as either part of the URL or as a parameter.

  • service_instance_id specifies from which service instance you a getting the configuration list.
  • subscription_id is a parameter that you set to your subscription ID.
  • include_config is a Boolean parameter that specifies whether or not to return the configuration details for every configuration in the list. If set to false, each configuration object will be returned as null, whereas if set to true, each configuration object will contain the full configuration state–about 200 lines each.

Postman: List Configurations

GET https://api.cloudservices.f5.com/waf/v1/app/{{service_instance_id}}/configuration/versions?subscription_id={{subscription_id}}&include_config=false

– RESPONSE

 {
     "configurations": [
         {
             "id": "cfg-aaW_SKUkCo",
             "service_instance_id": "waf-aagoB-gtVq",
             "configuration": null,
             "description": "Good configuration state",
             "create_time": "2020-06-30T23:06:05.763602Z"
         },
         ...
         {
             "id": "cfg-aac0TTnoeN",
             "service_instance_id": "waf-aagoB-gtVq",
             "configuration": null,
             "description": "Malicious IP updated",
             "create_time": "2020-06-30T23:01:52.161174Z"
         }
     ]
 }
  • id is the unique id for a specific configuration. It is used as the configuration_id to request this a specific configuration.
  • service_instance_id is the service instance that this configuration applies to.
  • configuration contains the details of the configuration, and is a copy of the waf_service object in the Essential App Protect schema, and it is the same configuration information shown in the portal in the Protect Application - JSON Configuration tab. It will be a null object if the request set the include_config parameter to false.
  • description is the information about that change that either you specified in update_comment when you made a configuration change, or a more generic description automatically added by the portal when you changed the configuration.
  • create_time is the date and time of the configuration change.

Get Configuration Details

This request returns a specific service instance configuration, similar to the List Configurations request.

  • service_instance_id specifies from which service instance you a getting the configuration.
  • configuration_id specifies which configuration you are requesting.
  • subscription_id is a parameter that you set to your subscription ID.

Postman: Get Configuration Details

GET https://api.cloudservices.f5.com/waf/v1/app/{{service_instance_id}}/configuration/versions/{{configuration_id}}?subscription_id={{subscription_id}}

– RESPONSE

{
    "id": "cfg-aaW_SKUkCo",
    "service_instance_id": "waf-aagoB-gtVq",
    "configuration": {
        "application": {...},
        "industry": "finance",
        "policy": {...},
    },
    "description": "Good configuration state",
    "create_time": "2020-06-30T23:06:05.763602Z"
}
  • configuration contains the details of the configuration. It is a copy of the waf_service object in the Essential App Protect schema, and it is the same configuration information shown in the portal in the Protect Application - JSON Configuration tab.

Attack Signature Service

Get Attack Signature Information with the API

The Essential App Protect API provides a path for getting attack signature information. The following request will return one page of up to 50 attack signatures, by default.

Postman: Get Attack Signature

GET https://api.cloudservices.f5.com/waf/v1/attack-signatures/signatures
{
    "signatures": [
        {
            "id": "200002195",
            "name": "SQL-INJ sysoledbusers",
            "rule": "",
            "last_updated": "2014/03/09 06:42:17",
            "apply_to": "Request",
            "attack_type": "SQL-Injection",
            "risk": 3,
            "accuracy": 1,
            "systems": [
                {
                    "name": "General Database"
                }
            ],
            "references": [
                {
                    "type": "url",
                    "id": "http://www.owasp.org/index.php/SQL_Injection"
                },
                {
                    "type": "url",
                    "id": "http://www.webappsec.org/projects/threat/classes/sql_injection.shtml"
                }
            ]
        },
        <!-- more attack signatures -->
    ],
    "page_size": 50,
    "page": 1,
    "count": 6021
}

You can add a query to change the response. For instance, to get the second page, use the following request.

Postman: Get All Attack Signatures

GET https://api.cloudservices.f5.com/waf/v1/attack-signatures/signatures?page=1&page_size=50

The page_size variable is not necessary, since the default is 50, but if you want to 20 get signatures per page, then you need to specify page_size=20 for all requests because page 2 is different for different pages sizes.

You can also get a signature by signature ID, as shown below:

Postman: Get Attack Signature

GET https://api.cloudservices.f5.com/waf/v1/attack-signatures/signatures?id=200010038

Most of the names in the response JSON can be used as query parameters, so for example you can ask for all attack signatures that have a risk of 3, or an attack_type of SQL-Injection, or an accuracy of 1. Note that values for the query parameters are case sensitive.


Service Events

Service events are changes to your service, whether you made them or they were made on your behalf by Essential App Protect. If you make a configuration change to your service instance, you have created a service event, and Essential App Protect will add the event to its list of service events and create a new configuration for the new state of your service. If F5 labs updates an attack signature in your service, that will also create a service event, but it will not create a new configuration because your configuration has remained the same (you still have the same policy and options).

Postman: Get Service Events

POST https://api.cloudservices.f5.com/waf/v1/service-events

– PAYLOAD

{
    "service_instance_id": "waf-aagoB-gtVq",
    "subscription_id": "s-aawgtryfof",
    "since": "2020-06-30T17:35:11Z",
    "until": "2020-07-02T17:35:11Z"
}
  • service_instance_id specifies from which service instance you are getting the service events.
  • subscription_id is your subscription ID.
  • since and until specify the time range for the returned list of service events. until will default to the current date and time, so if you want the service events for the last two days, set since to the current time minus two days, and leave until unspecified.

– RESPONSE

{
    "total_size": 8,
    "events": [
        {
            "type": "CONFIGURATION",
            "service_instance_id": "waf-aagoB-gtVq",
            "subscription_id": "s-aawgtryfof",
            "description": "Good configuration state",
            "details": "",
            "date_time": "2020-07-01T21:58:19.569986Z",
            "event_id": "92a92af8-c0bb-41d0-b45b-cdc5cb4e9ff3",
            "user_id": "u-aaiJJFFvZE",
            "user_name": "Olivia Userton",
            "user_email": "g.roberts@f5.com",
            "config_version_id": "cfg-aa79E3nqoI"
        },
        {
            "type": "SYSTEM",
            "service_instance_id": "waf-aagoB-gtVq",
            "subscription_id": "s-aawgtryfof",
            "description": "Attack signature file 20200630_100835 updated",
            "details": "",
            "date_time": "2020-07-01T11:35:07.550649Z",
            "event_id": "ae7ab171-d83c-401f-ba01-30463a6edc69",
            "user_id": "System",
            "user_name": "System ",
            "user_email": "",
            "config_version_id": ""
        },
        ...
    ]
}
  • total_size is the number of service events returned.
  • events is an array holding the list of individual events.
    • type tells you the cause of this service event and can be either “CONFIGURATION”, if this entry was caused by a user change, or “SYSTEM” if the event was caused by a system-level change or update.
    • description is an explanation of the configuration change, or blank for a system event.
    • details is a blank string.
    • date_time is the date and time of when the event occurred.
    • event_id is a unique ID for the event.
    • user_id is the system ID for the user who made a configuration change, or “System” for a system event.
    • user_name is the name of the user who made a configuration change, or “System” for a system event.
    • user_email is the email address for the user that made a configuration change, or an empty string for a system event.
    • config_version_id is the unique id for the specific configuration resulting from a configuration event, or blank for a system event. A non-blank config_version_id can be used to request the specific service configuration resulting from this configuration event (see Get Configuration Details).

Threat Campaigns Service

The Threat Campaign Service allows you to get information about threat campaigns that Essential App Protect uses to protect your application.

List Threat Campaigns

This request will return this list of all threat campaigns currently used by Essential App Protect. This request will return over 400 threat campaigns and about 10,000 lines of JSON. Each threat campaign will have a unique cmpid that can be used to get information on individual threat campaigns with Get Threat Campaign by ID or to modify your security policy.

Postman: List Threat Campaigns

GET https://api.cloudservices.f5.com/waf/v1/threat-campaigns/campaigns

– RESPONSE

{
    "campaigns": [
        {
            "cmpid": "cmp2684b2bac06be9d027fad69009f7d4a6",
            "display_name": "Horde Imp Unauthenticated Remote Command Execution - Down",
            "description": "This campaign aims to exploit Horde Imp, an application that comes with the Horde GroupWare/Webmail suite.  The application contains a remote code execution vulnerability that allows a threat actor to issue unauthenticated IMAP requests to arbitrary hosts. The threat actor tries to download a malicious file on the vulnerable server.\n",
            "intent": "Malware Spreading - Generic",
            "risk": "HIGH",
            "attack_type": "Server Side Code Injection",
            "first_observed": "2019-01-17T10:24:00Z",
            "last_observed": null,
            "target_info": "",
            "systems": [
                {
                    "name": "PHP"
                }
            ],
            "references": [
                {
                    "type": "cve",
                    "value": "CVE-2008-4182",
                    "is_clickable": 1
                }
            ]
        },
        ...
    ]
}

Get Threat Campaign by ID

This request will return all information on the requested campaign id (cmpid).

Postman: Get Threat Campaign by ID

GET https://api.cloudservices.f5.com/waf/v1/threat-campaigns/{{cmpid}}

– RESPONSE

{
    "cmpid": "cmp5a66c6d30a5e400ebf8110699d4f911b",
    "display_name": "Robots.txt scanner - YPF882",
    "description": "This campaign uses a bot that scans for robots.txt files on multiple websites, then uses multiple user agent strings and sends a very unique cookie header: YPF8827340282Jdskjhfiw_928937459182JAX666. Robots.txt files usually contain the list of the URLs in the web application, which site administrators don't want the search engines to index, like management interfaces and other critical locations.\n",
    "intent": "Vulnerable System Reconnaissance",
    "risk": "HIGH",
    "attack_type": "Vulnerability Scan",
    "first_observed": "2016-11-30T14:27:31Z",
    "last_observed": null,
    "target_info": "Webservers with robots.txt file",
    "systems": [
        {
            "name": "All systems"
        }
    ],
    "references": []
}

Get Threat Campaign Report

This request will return a list of all threat campaigns and a list of actors using those campaigns.

Postman: Get Threat Campaign Report

POST https://api.cloudservices.f5.com/waf/v1/threat-campaigns/report

– PAYLOAD

{
  "since": "2020-06-08T04:21:52Z",
  "until": "2020-06-10T21:00:00Z"
}
  • since and until specify the time range for the returned list of actors. since will default to the beginning of time, and until will default to the current date and time. If you don’t specify a payload, the request will return all actors who have used those campaigns.

– RESPONSE

{
    "campaigns": {
        "total": "409",
        "active": [
            {
                "cmpid": "cmp6147f9d3096cc472fbd824ecd92ae5c7",
                "display_name": "Spring Data Commons RCE - Touch",
                "actors": "93"
            },
            {
                "cmpid": "cmpb89507a4a51cc406b31b29eb2ada696c",
                "display_name": "Apache Struts2 devmode RCE - HatBoy",
                "actors": "1"
            },
            ...
        ]
    },
    "actors": [
        {
            "geo_latitude": -33.8671,
            "geo_longitude": 151.207,
            "geo_country_code": "AU",
            "cmpid": "cmp02e56c12d374d9e7d17bced2df4e496b",
            "display_name": "ThinkPHP Remote Code Execution - uname"
        },
        {
            "geo_latitude": 39.0329,
            "geo_longitude": -77.4866,
            "geo_country_code": "US",
            "cmpid": "cmp6147f9d3096cc472fbd824ecd92ae5c7",
            "display_name": "Spring Data Commons RCE - Touch"
        },
        ...
    ]
}

Solutions

Modify a Service Instance

If you want to change some aspect of your Essential App Protect service instance, you will update your subscription. Updating a subscription is essentially the same as creating a subscription, except you use the PUT method rather than the POST method, you specify the subscription you want to modify, and the payload contains the same JSON but with the modification(s).

For instance, if you only want to change the name of your service instance, you would change the service_instance_name value to the new name, and then you would issue the following PUT request. You can also add an update_comment to make it easier to see what changed.

Postman: Update Subscription HTTP or Update Subscription HTTPS

PUT https://api.cloudservices.f5.com/v1/svc-subscription/subscriptions/{{SUBSCRIPTION_ID}}

– PAYLOAD

{
    "account_id": "a-aaQgt6MlaD",
    "catalog_id": "c-aa9N0jgHI4",
    "service_type": "waf",
    "service_instance_name": "New Service Instance Name",
    "configuration": {
        "update_comment": "Updated Service Instance Name",
        <!-- the configuration is unchanged -->
    }
}

If you do not know your subscription ID, you can retrieve it by requesting all Essential App Protect subscriptions and selecting the appropriate ID: Get All Essential App Protect Subscriptions.

For more examples of specific modifications, see the following sections:

Delete/retire an Essential App Protect Service Instance

The first step is to remove the CNAME record in your DNS settings that redirects your application’s traffic through your Essential App Protect Service instance. For more information, see Protect Application - DNS Settings, Step 2.

Important

When you suspend or retire a subscription, you are turning off all functions of the Essential App Protect Service instance for your application. That also means that if you still have the CNAME record in your DNS settings that you added when you created your Essential App Protect service instance, all of your application’s traffic will be going through a non-functional proxy, effectively blocking all communication with your application. It is very important that you remove the CNAME record from your DNS settings prior to suspending or retiring an Essential App Protect Service instance.

“Deleting” a service with the API is done by retiring the service instance based on its subscription ID. The subscription ID gets created as part of the service instance creation and returned in the response JSON as subscription_id.

Postman: Subscription Retire

POST https://api.cloudservices.f5.com/v1/svc-subscription/subscriptions/{{subscription_id}}/retire

– RESULT

{
    "status": "RETIRED",
    "service_state": "DEPLOYED",
    "subscription_id": "s-aawgtryfof"
}

Suspend an Essential App Protect Service Instance

The first step is to remove the CNAME record in your DNS settings that redirects your application’s traffic through your Essential App Protect Service instance. For more information, see Protect Application - DNS Settings, Step 2.

When you suspend an Essential App Protect service instance, you are turning it off. Suspending a service will change its state to UNDEPLOYED in the API and Inactive in the portal, but the service will continue to exist in your list of services. Once suspended, the service will not perform any actions, and it will not act as a pass through to your application.

Important

When you suspend or retire a subscription, you are turning off all functions of the Essential App Protect Service instance for your application. That also means that if you still have the CNAME record in your DNS settings that you added when you created your Essential App Protect service instance, all of your application’s traffic will be going through a non-functional proxy, effectively blocking all communication with your application. It is very important that you remove the CNAME record from your DNS settings prior to suspending or retiring an Essential App Protect Service instance.

To suspend an application, use the following request. Remember to change the subscription_id to the one assigned to the service instance you want to suspend.

Postman: Subscription Suspend

POST https://api.cloudservices.f5.com/v1/svc-subscription/subscriptions/{{subscription_id}}/suspend

– RESULT

{
    "status": "ACTIVE",
    "service_state": "UNDEPLOYING",
    "subscription_id": "s-aawgtryfof"
}

After a few moments, the service_state will become “UNDEPLOYED”, which you can verify by getting the subscription status. You can later “unsuspend” by activating the subscription for this service instance.

POST https://api.cloudservices.f5.com/v1/svc-subscription/subscriptions/{{subscription_id}}/activate

– RESPONSE

{
   "status": "ACTIVE",
   "service_state": "DEPLOYING",
   "subscription_id": "s-aawgtryfof"
}

Get All Essential App Protect Subscriptions

This request is useful for seeing all Essential App Protect service instances at once. For example, this request would allow you to find the subscription ID for a particular service instance or verify that you have blocking enabled for all service instances.

Postman: Get All WAF Subscriptions

GET https://api.cloudservices.f5.com/v1/svc-subscription/subscriptions?catalogId=c-aa9N0jgHI4&account_id={{ACCOUNT_ID}}&service_type=waf

– RESULT

{
    "subscriptions": [
        {
            "subscription_id": "s-aawgtryfof",
            "account_id": "a-aaQgt6MlaD",
            "user_id": "u-aaiJJFFvZE",
            "catalog_id": "c-aa9N0jgHI4",
            "service_instance_id": "waf-aagoB-gtVq",
            "status": "ACTIVE",
            "service_instance_name": "Example Application",
            "deleted": false,
            "service_type": "waf",
            "configuration": {
                <!-- service specific configuration content -->
            },
            <!-- service specific content -->
        },
        {
            "subscription_id": "s-aaVf7muxD9",
            "account_id": "a-aaQgt6MlaD",
            "user_id": "u-aaiJJFFvZE",
            "catalog_id": "c-aa9N0jgHI4",
            "service_instance_id": "waf-aaOjMlcBmW",
            "status": "ACTIVE",
            "service_instance_name": "Example2",
            "deleted": false,
            "service_type": "waf",
            "configuration": {
                <!-- service specific configuration content -->
            },
            <!-- service specific content -->
        },
    ],
    <!-- additional subscriptions -->
}

Protect Sensitive Information and Parameters

Essential App Protect provides two mechanisms for masking sensitive information: Data Guard and Sensitive Parameters.

Data Guard: In some web applications, a response may contain sensitive user information, such as credit card numbers or social security numbers. The Data Guard feature can prevent responses from exposing sensitive information by masking the data (this is also known as response scrubbing). Data Guard scans text in responses looking for the types of sensitive information that you enable and then masks the value in the response to obscure from all downstream views or logs. Essential App Protect provides protection for credit cards if Data Guard is enabled and “cc” and “ssn” are turned on.

Sensitive Parameters: Traffic between an application server and a web server can have many parameters that contain sensitive information. In addition to credit cards and social security numbers, you might have account numbers, passwords, medical, or any privacy information that you don’t want to expose. By adding these parameter names to the sensitive parameters list, Essential App Protect will mask the contents of those parameters from any display or logging that is performed as part of the service. Unlike Data Guard, the Sensitive Parameters feature will not change the parameter value that is passed between the application server and web server.

Essential App Protect defaults to enabling Data Guard and Sensitive Parameters, but there are no parameters declared as sensitive. You can add parameters to the list using either the API or the portal. To make changes through the portal, click on the PROTECT APPLICATION card on the Essential App Protect dashboard while viewing your protected application, and make your changes in the COMPLIANCE & PRIVACY section of the General tab–compliance details. You can also follow the API change instructions below, and apply those changes in the JSON configuration tab.

To change compliance settings with the API, you can simply change the data_guard and sensitive_parameters variables in the policy/compliance_enforcement and policy/sensitive_parameters sections of the Essential App Protect subscription update payload, as shown below:

Postman: Update Subscription HTTP or Update Subscription HTTPS

PUT https://api.cloudservices.f5.com/v1/svc-subscription/subscriptions/{{SUBSCRIPTION_ID}}

– PAYLOAD:

{
    "service_type": "waf",
    "service_instance_name": "{PROTECTED_APP}",
    "configuration": {
        "waf_service": {
            ...
            "policy": {
                "compliance_enforcement": {
                    "data_guard": {
                        "cc": true,
                        "enabled": true,
                        "ssn": true
                    },
                    "sensitive_parameters": {
                        "enabled": true,
                        "parameters": [
                           "password",
                           "creditcard"
                        ]
                    }
                },
            ...
           }
        }
    }
}

This will flag these parameters as sensitive parameters. When you create sensitive parameters, the system replaces the sensitive data in the stored request and in logs with asterisks (***), keeping the sensitive data in these parameters private.


Add Multiple IP Endpoints for an Application

This is done by modifying the JSON to include multiple IP endpoints. In the portal, use the JSON Configuration section to modify the JSON. The API solution is basically the same–modify the payload JSON to have multiple endpoints, and either create or modify the subscription. See the JSON example below showing multiple IP endpoints.

Use this API request to create a subscription instance with multiple endpoints:

Postman: Update Subscription HTTP or Update Subscription HTTPS

POST https://api.cloudservices.f5.com/v1/svc-subscription/subscriptions

or this one to add endpoints to an existing instance:

PUT https://api.cloudservices.f5.com/v1/svc-subscription/subscriptions/{{subscription_id}}

– PAYLOAD

{
    ...
    "configuration": {
        "waf_service": {
                ...
                "waf_regions": {
                    "aws": {
                        "us-east-1": {
                            "endpoint": {
                                "dns_name": "<region1.yourdomain.com>",
                                "http": {
                                    "enabled": true,
                                    "port": 8080
                                },
                                "https": {
                                    "enabled": true,
                                    "port": 4443
                                }
                            }
                        },
                        "us-west-2": {
                            "endpoint": {
                                "dns_name": "<region2.yourdomain.com>",
                                "http": {
                                    "enabled": true,
                                    "port": 8080
                                },
                                "https": {
                                    "enabled": true,
                                    "port": 4443
                                }
                            }
                        }
                    }
        ...
}

Delete an SSL/TLS Certificate

Unused certificates can be deleted with the API using the following request. You will need the certificate_id to specify which certificate you would like to delete.

Postman: Delete Certificate

DELETE https://api.cloudservices.f5.com/v1/svc-certificates/{certificate_id}

If the certificate was not being used, you will get response code 200 indicating it was deleted. If the certificate is still in use, you will get response code 400 with the error message, “Certificate is still in use.”

If you do not know the certificate_id, you can get a list of all certificates in your account and their associated IDs with this request:

Postman: Get Account Certificates

GET https://api.cloudservices.f5.com/v1/svc-certificates/certificates/{account_id}

– RESULT

{
    "certificates": [
        {
            "id": "cert-aaQgtCI-Px",
            "common_name": "certificate-1",
            "account_id": "",
            "expiration_date": "2027-10-24T19:25:53Z"
        },
        ...
        {
            "id": "cert-aaLewZcv3X",
            "common_name": "certificate-n",
            "account_id": "",
            "expiration_date": "2027-10-24T19:25:53Z"
        }
    ]
}

Globally Disable an Attack Signature

You can disable an attack signature by adding it to the exceptions in your policy for High-risk Attack Mitigation using either the API or the JSON configuration tab in the portal. You will need the signature ID for the attack signature you want to disable, which you can find in the Attack Signatures Table. For example, if you want to disable two attack signatures, 200100064 and 200010038, you would simply add these to the exceptions section in the JSON, as shown below.

Postman: Update Subscription HTTP or Update Subscription HTTPS

PUT https://api.cloudservices.f5.com/v1/svc-subscription/subscriptions/{{subscription_id}}

– PAYLOAD

{
    "account_id": "a-aaQgt6MlaD",
    "catalog_id": "c-aa9N0jgHI4",
    "service_type": "waf",
    "service_instance_name": "My application",
    "configuration": {
        "waf_service": {
            "application": { ... },
            "industry": "finance",
            "policy": {
                "encoding": "utf-8",
                "compliance_enforcement": { ... },
                "high_risk_attack_mitigation": {
                    "enabled": true,
                    "enforcement_mode": "blocking",
                    "signature_enforcement": { ... },
                    "allowed_methods": { ... },
                    "disallowed_file_types": { ... },
                    "http_compliance_enforcement": { ... },
                    "websocket_compliance_enforcement": { ... },
                    "geolocation_enforcement": { ... },
                    "ip_enforcement": { ... },
                    "exceptions": {
                        "attack_signatures": [
                            {
                                "id": "200100064",
                                "enabled": false
                            },
                            {
                               "id": "200010038",
                                "enabled": false
                            }
                        ]
                    }
                },
                "malicious_ip_enforcement": { ... },
                "threat_campaigns": { ... },
            }
        }
    }
}

Redirect HTTP traffic to HTTPS

To redirect traffic using the API, you can setup the JSON payload as shown below, and update the subscription. In order to redirect traffic from HTTP to HTTPS, you must enable both an HTTP and an HTTPS port, and you must set the https_redirect value to true. Also, in order to enable an HTTPS port, you’ll need to specify a certificate_id, if you haven’t already done so.

PUT https://api.cloudservices.f5.com/v1/svc-subscription/subscriptions/{{subscription_id}}

– PAYLOAD

{
     "application": {
         "description": "",
             "fqdn": "example.com",
         "http": {
             "enabled": true,
             "https_redirect": true,
             "port": 80
         },
         "https": {
             "enabled": true,
             "port": 443,
             "tls": {
                 "certificate_id": "cert-aaQgtCI-Px"
             }
         },
         "waf_regions": { ... }
     },
     "policy": { ... }
}

Note

For information on how to redirect traffic using the portal, go to the Protect Application - General section and view the LISTENER SETTINGS topic. Alternatively, you can redirect traffic via the JSON configuration using the JSON settings shown above in the API instructions.


Roll Back Configuration Changes

Essential App Protect stores all configuration changes you make as individual configuration states enabling you to implement undo/redo and rollback capabilities. The workflow is as follows.

  1. Request a list of the past configuration states. The first configuration in the list is the one currently in use, so select the previous one for undo or select one further back for a rollback.
  2. Get the configuration details of the one you choose.
  3. Update your subscription with that configuration state as the new configuration.

These steps are outlines below.

1a. Get the list of configurations - Method A (see Get Configuration Details for request details)

Use this method to for a simple solution.

GET https://api.cloudservices.f5.com/waf/v1/app/{{service_instance_id}}/configuration/versions?subscription_id={{subscription_id}}&include_config=true

– RESPONSE

 {
     "configurations": [
         {
             "id": "cfg-aaW_SKUkCo",
             "service_instance_id": "waf-aagoB-gtVq",
             "configuration": null,
             "description": "Malicious IP updated",
             "create_time": "2020-06-30T23:06:05.763602Z"
         },
         ...
         {
             "id": "cfg-aac0TTnoeN",
             "service_instance_id": "waf-aagoB-gtVq",
             "configuration": null,
             "description": "Good configuration state",
             "create_time": "2020-06-30T23:01:52.161174Z"
         },
         ...
     ]
 }

Save the id value of the configuration you want to roll back to (configuration_id).

1b. Get the list of configurations - Method B (see Service Events for request details)

Use this method if you need some of the extra information returned in the response JSON or if you want to narrow your results to a specific date/time range.

POST https://api.cloudservices.f5.com/waf/v1/service-events

– PAYLOAD

{
    "service_instance_id": "waf-aagoB-gtVq",
    "subscription_id": "s-aawgtryfof",
    "since": "2020-06-30T17:35:11Z",
    "until": "2020-07-02T17:35:11Z"
}

– RESPONSE

{
    "total_size": 8,
    "events": [
        {
            "type": "CONFIGURATION",
            "service_instance_id": "waf-aagoB-gtVq",
            "subscription_id": "s-aawgtryfof",
            "description": "Malicious IP updated",
            "details": "",
            "date_time": "2020-06-30T23:06:05.763602Z",
            "event_id": "92a92af8-c0bb-41d0-b45b-cdc5cb4e9ff3",
            "user_id": "u-aaiJJFFvZE",
            "user_name": "Olivia Userton",
            "user_email": "o.userton@f5.com",
            "config_version_id": "cfg-aaW_SKUkCo"
        },
        {
            "type": "CONFIGURATION",
            "service_instance_id": "waf-aagoB-gtVq",
            "subscription_id": "s-aawgtryfof",
            "description": "Good configuration state",
            "details": "",
            "date_time": "2020-06-30T23:01:52.161174Z",
            "event_id": "ae7ab171-d83c-401f-ba01-30463a6edc69",
            "user_id": "u-aaiJJFFvZE",
            "user_name": "Olivia Userton",
            "user_email": "o.userton@f5.com",
            "config_version_id": "cfg-aac0TTnoeN"
        },
        ...
    ]
}

Save the config_version_id value of the configuration you want to roll back to (configuration_id).

2. Get the configuration details (see Get Configuration Details for request details)

Use the configuration_id you saved in step one to modify the URL in the following request.

GET https://api.cloudservices.f5.com/waf/v1/app/{{service_instance_id}}/configuration/versions/{{configuration_id}}?subscription_id={{subscription_id}}

– RESPONSE

{
    "id": "cfg-aaW_SKUkCo",
    "service_instance_id": "waf-aagoB-gtVq",
    "configuration": {
        "application": {...},
        "industry": "finance",
        "policy": {...},
    },
    "description": "Good configuration state",
    "create_time": "2020-06-30T23:06:05.763602Z"
}

Save the configuration object from the response JSON. This is the configuration you want to restore.

3. Update your subscription with the retrieved configuration

The configuration object from step 2 is a copy of the waf_service in the Essential App Protect schema from the state of your service instance at that time. In order to roll back to that state, simply change the waf_service object in the payload for the update subscription request to the configuration object you saved in step 2, as shown below. You should also provide an appropriate update_comment to make future rollbacks easy.

PUT https://api.cloudservices.f5.com/v1/svc-subscription/subscriptions/{{subscription_id}}

– PAYLOAD

{
    "service_type": "waf",
    "service_instance_name": "ExampleRM",
    "configuration": {
        "update_comment": "Roll back to cfg-aac0TTnoeN",
        "waf_service": {
            "application": {...},
            "industry": "finance",
            "policy": {...}
       }
    }
}