NGINX Documentation

Configuration Guide

Overview

This guide explains the NGINX App Protect security features and how to use them. This guide also assumes that you have some familiarity with various Layer 7 (L7) Hypertext Transfer Protocol (HTTP) concepts, such as Uniform Resource Identifier (URI)/Uniform Resource Locator (URL), method, header, cookie, status code, request, response, and parameters.

For more information on the NGINX App Protect security features, see NGINX App Protect Terminology.

Best Practices

When configuring NGINX App Protect, app_protect_enable should always be enabled in a proxy_pass location. If configuration returns static content, it is recommended to add a location which enables App Protect, and proxies the request via proxy_pass to the internal static content location. An example can be found in Configure Static Location.

Supported Security Policy Features

The following security features are supported in NGINX App Protect. We show what is enabled in the default policy and the changes that the user can do on top of this policy.

Protection Mechanism Description
Attack Signatures Default policy covers all the OWASP top 10 attack patterns enabling signature sets detailed in a section below. The user can disable any of them or add other sets.
Signature attack for Server Technologies Support adding signatures per added server technology.
Threat Campaigns These are patterns that detect all the known attack campaigns. They are very accurate and have almost no false positives, but are very specific and do not detect malicious traffic that is not part of those campaigns. The default policy enables threat campaigns but it is possible to disable it through the respective violation.
HTTP Compliance All HTTP protocol compliance checks are enabled by default except for GET with body and POST without body. It is possible to enable any of these two. Some of the checks enabled by default can be disabled, but others, such as bad HTTP version and null in request are perfomed by NGINX parser and NGINX App Protect only reports them. These checks cannot be disabled.
Evasion Techniques All evasion techniques are enabled by default and each can be disabled. These include directory traversal, bad escaped character and more.
Data Guard Detects and masks credit card and/or US social security numbers in responses. Disabled by default but can be enabled.
Parameter parsing Support only auto-detect parameter value type and acts according to the result: plain alphanumeric string, XML or JSON.
Disallowed meta characters Detected in parameter names, parameter values, URLs, headers and in JSON and XML content. Metacharacters indicate suspicious traffic, but not necessarily an actual threat. It is the combination of meta characters, attack signatures and other violations that indicates an actual threat that should be blocked and this is determined by Violation Rating. See section below.
Disallowed file type extension Support any file type. Default includes a predefined list of file types. See Disallowed File Types list below.
Cookie enforcement By default all cookies are allowed and not enforced for integrity. The user can add specific cookies, wildcards or explicit, that will be enforced for integrity. It is also possible to set the cookie attributes: HttpOnly, Secure and SameSite for cookies found in the response.
Sensitive Parameters Default policy masks the “password” parameter in the security log. It is possible to add more such parameters.
JSON Content JSON content profile detects malformed content and detects signatures and metacharacters in the property values. Default policy checks maximum structure depth. It is possible to enable more size restrictions: maximum total length Of JSON data; maximum value length; maximum array length; tolerate json parsing errors. JSON parameterization and schema enforcement is not supported.
XML Content XML content profile detects malformed content and detects signatures in the element values. Default policy checks maximum structure depth. It is possible to enable more size restrictions: maximum total length of XML data, maximum number of elements are more. SOAP, Web Services and XML schema features are not supported.
Allowed methods Check HTTP allowed methods. By default all the standard HTTP methods are allowed.
Deny & Allow IP listing Manually define denied & allowed IP addresses.
Trust XFF header Disabled by default. User can enable it and optionally add a list of custom XFF headers.

Disallowed File Types

The following file types are disallowed by default:

  • bak, bat, bck, bkp, cfg, conf, config, ini, log, old, sav, save, temp, tmp
  • bin, cgi, cmd, com, dll, exe, msi, sys, shtm, shtml, stm
  • cer, crt, der, key, p12, p7b, p7c, pem, pfx
  • dat, eml, hta, htr, htw, ida, idc, idq, nws, pol, printer, reg, wmz

Additional Policy Features

Feature Description
Enforcement by Violation Rating By default block requests that are declared as threats, that is, their Violation Rating is 4 or 5. It is possible to change this behavior: either disable enforcement by Violation Rating or block also request with Violation Rating 3 - needs examination. See section on basic configuration below.
Request size checks Upper limit of request size as dictated by the maximum buffer size of 10 MB; Size checks for: URL, header, Query String, whole request (when smaller than the maximum buffer), cookie, POST data. By default all the checks are enabled with the exception of POST data and whole request. The user can enable or disable every check and customize the size limits.
Malformed cookie Requests with cookies that are not RFC compliant are blocked by default. This can be disabled.
Status code restriction Illegal status code in the range of 4xx and 5xx. By default only these are allowed: 400, 401, 404, 407, 417, 503. The user can modify this list or disable the check altogether.
Blocking pages The user can customize all blocking pages. By default the AJAX response pages are disabled, but the user can enable them.

Configuring Attack Signatures

App Protect includes predefined attack signatures to protect your application against all attack types identified by the system. As new attack signatures are identified, they will become available for download so that your system will always have the most up-to-date protection. You can update the attack signatures without updating the App Protect release, and conversely, you can update App Protect without changing the attack signature package, unless you moved to a new NGINX Plus release.

Signature Settings

Setting JSON Property in Policy Support in NGINX App Protect Value in Default Profile
Signature Sets signature-sets All available sets. See signature set list below
Signatures signatures “Enabled” flag can be modified. All signatures in the included sets are enabled.
Auto-Added signature accuracy minimumAccuracyForAutoAddedSignatures Editable Low
Attack Signature False Positive Mode attackSignatureFalsePositiveMode Editable detect-and-allow

Signature Sets in Default Policy

The following signature sets are included in the default policy. Most of the sets are defined by the Attack Type they protect from. In all sets the Alarm flag is enabled and Block disabled except High Accuracy Signatures, which are set to blocked (Block flag is enabled).

  • Command Execution Signatures
  • Cross Site Scripting Signatures
  • Directory Indexing Signatures
  • Information Leakage Signatures
  • OS Command Injection Signatures
  • Path Traversal Signatures
  • Predictable Resource Location Signatures
  • Remote File Include Signatures
  • SQL Injection Signatures
  • Authentication/Authorization Attack Signatures
  • XML External Entity (XXE) Signatures
  • XPath Injection Signatures
  • Buffer Overflow Signatures
  • Denial of Service Signatures
  • Vulnerability Scanner Signatures
  • High Accuracy Signatures
  • All CVE Signatures

Basic Signature Sets Included in App Protect

These signatures sets are included but are not part of the default template.

  • All Response Signatures
  • All Signatures
  • Generic Detection Signatures
  • Generic Detection Signatures (High Accuracy)
  • Generic Detection Signatures (High/Medium Accuracy)
  • High Accuracy Signatures
  • Low Accuracy Signatures
  • Medium Accuracy Signatures
  • OWA Signatures
  • WebSphere signatures

Policy Configuration

The NGINX App Protect ships with two reference policies:

  • The default policy which is identical to the base template and provides the OWASP Top 10 security protection out of the box.
  • The strict policy contains more restrictive criteria for blocking traffic than the default policy. It is meant to be used for protecting sensitive applications that require more security but with higher risk of false positives. You can use those policies as is, but usually you will use them as starting points and further customize them to the needs of the applications they protect.

Overview

The NGINX App Protect security policy configuration uses the declarative format based on a pre-defined base template. The policy is represented in a JSON file which you can edit to add, modify and remove security capabilities with respect to the base template. The way the policy is integrated into the NGINX configuration is via referencing the JSON file (using the full path) in the nginx.conf file.

In the following example, the NGINX configuration file with App Protect enabled in the HTTP context and the policy /etc/nginx/NginxDefaultPolicy.json is used:

user nginx;
worker_processes  4;

load_module modules/ngx_http_app_protect_module.so;

error_log /var/log/nginx/error.log debug;
working_directory /tmp/cores;
worker_rlimit_core 1000M;

events {
    worker_connections  65536;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    app_protect_enable on; # This is how you enable NGINX App Protect in the relevant context/block
    app_protect_policy_file "/etc/nginx/NginxDefaultPolicy.json"; # This is a reference to the policy file to use. If not defined, the default policy is used
    app_protect_security_log_enable on; # This section enables the logging capability
    app_protect_security_log "/etc/app_protect/conf/log_default.json" syslog:server=127.0.0.1:515; # This is where the remote logger is defined in terms of: logging options (defined in the referenced file), log server IP, log server port

    server {
        listen       80;
        server_name  localhost;
        proxy_http_version 1.1;

        location / {
            client_max_body_size 0;
            default_type text/html;
            proxy_pass http://172.29.38.211:80$request_uri;
        }
    }
}

Basic Configuration and the Default Policy

The base template is the common starting point to any policy you write. The default policy just reflects that template without any further modifications, thus we use the terms base template and default policy interchangeably. The default policy can be found in: /etc/nginx/NginxDefaultPolicy.json.

The default policy enforces violations by Violation Rating, the App Protect computed assessment of the risk of the request based on the triggered violations.

  • 0: No violation
  • 1-2: False positive
  • 3: Needs examination
  • 4-5: Threat

The default policy enables most of the violations with Alarm turned on, but not Block. By default, if the violation rating is 4-5 the request is blocked using the VIOL_RATING_THREAT violation. By default, all other requests are not blocked. This is to minimize false positives. However, you can change the default behavior. For example, if you want to add blocking on a violation rating of 3 as well, enable blocking for the VIOL_RATING_NEED_EXAMINATION violation. The High Accuracy signatures that block a request regardless of its Violation Rating are an exception to this.

The Strict Policy

The Strict Policy is recommended as a starting point for applications requiring a higher level of security. Just like all other policies it is based on the base template, so it detects and blocks everything the default policy does. It can be found in: /etc/nginx/NginxStrictPolicy.json.

In addition the Strict Policy also blocks the following:

  • Requests that have a Violation Rating of 3, “Needs examination”. This occurs because the VIOL_RATING_NEED_EXAMINATION violation’s block flag is enabled in the strict policy.
  • Requests with the VIOL_EVASION violation (evasion techniques).
  • Requests with violations that restrict options in the request and response: HTTP method, response status code and disallowed file types.

Note: Other violations, specifically attack signatures and metacharacters, which are more prone to false positives, still have only Alarm turned on, without blocking, contributing to the Violation Rating as in the Default policy.

In addition, the Strict policy also enables the following features in alarm only mode:

  • Data Guard: masking Credit Card and US Social Security numbers found in HTTP responses.
  • HTTP response data leakage signatures: preventing exfiltration of sensitive information from the servers.
  • More restrictive limitations: mainly sizing and parsing of JSON and XML payloads.
  • Cookie attribute insertion: the Strict policy adds the Secure and SameSite=lax attributes to every cookie set by the application server. These attributes are enforced by the browsers and protect against session hijacking and CSRF attacks respectively.

Policy Authoring and Tuning

The policy JSON file specifies the settings that are different from the base template, such as enabling more signatures, disabling some violations, adding server technologies, etc. These will be shown in the next sections.

There are two ways to tune those settings:

  • Within the policy structure property, the organic structure of the policy.
  • Within the modifications structure property that contains a list of changes expressed in a generic manner.

Both options are equivalent in their semantic expression power, but different syntactically and are designated for different use cases. But before that, let’s look at an example - disabling a specific attack signature.

Signature 200001834 disabled in the policy property:

{
    "policy": {
        "name": "signature_exclude_1",
        "signatures": [
            {
                "signatureId": 200001834,
                "enabled": false
            }
        ]
    }
}

As you can see, this is expressed using the signatures property that contains configuration of individual signatures in a policy. If you want to modify other parts of the policy, you would use different JSON properties.

The same configuration in the modifications array looks like this:

{
    "policy": {
        "name": "signature_exclude_2"
    },
    "modifications": [
        {
            "entityChanges": {
                "enabled": false
            },
            "entity": {
                "signatureId": 200001834
            },
            "entityType": "signature",
            "action": "add-or-update"
        }
    ]
}

Note the generic schema that can express manipulation in any policy element: entity, entityType, action etc. The modifications array is a flat list of individual changes applied to the policy after evaluating the policy block.

So when to use policy and when to use modifications? There are some recommended practice guidelines for that:

  • Use policy to express the security policy as you intended it to be: the features you want to enable, disable, the signature sets, server technologies and other related configuration attributes. This part of the policy is usually determined when the application is deployed and changes at a relatively slow pace.
  • Use modifications to express exceptions to the intended policy. These exceptions are usually the result of fixing false positive incidents and failures in tests applied to those policies. Usually these are granular modifications, typically disabling checks of individual signatures, metacharacters and sub-violations. These changes are more frequent.
  • Use modifications also for removing individual collection elements from the base template, for example disallowed file types.

It is a good practice to separate the modifications to a different file and have the main policy file reference the former, as the two parts have different lifecycles.

The sections just below review the common policy feature configurations using examples. For the full reference of the policy JSON properties see the Declarative Policy guide.

Policy Enforcement Modes

A policy’s enforcement mode can be:

  • Blocking: Any illegal or suspicious requests are logged and blocked.
  • Transparent: Any illegal or suspicious requests are logged but not blocked.

Specific security features can be defined as blocked or transparent in the policy.

Blocking Mode example:

{
    "policy": {
        "name": "policy_name",
        "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking"
    }
}

Transparent Mode example:

{
    "policy": {
        "name": "policy_name",
        "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
        "applicationLanguage": "utf-8",
        "enforcementMode": "transparent"
    }
}

Enabling Violations

Adding and enabling additional security features to the policy can be done by specifying the violation name and the alarm block state to “true”. To set different states to sub-violations within the violation, enable the violation first, then specifying and enable the sub-violations. Also, a violation may have its own section that provides additional configuration granularity for a specific violation/sub-violation. The examples below show how to enable a violation and sub-violation in a declarative format.

Configuration Details Example

In this example, we enable 2 violations: VIOL_JSON_FORMAT and VIOL_PARAMETER_VALUE_METACHAR.

Note that the example defines the blocking and alarm setting for each violation. These settings override the default configuration set above in the enforcementMode directive. Be aware, however, that in a transparent policy no violations are blocked, even if specific violations are set to block: true in the configuration.

{
   "policy": {
       "name": "policy_name",
       "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
       "applicationLanguage": "utf-8",
       "enforcementMode": "blocking",
       "blocking-settings": {
           "violations": [
               {
                   "name": "VIOL_JSON_FORMAT",
                   "alarm": true,
                   "block": true
               },
               {
                   "name": "VIOL_PARAMETER_VALUE_METACHAR",
                   "alarm": false,
                   "block": false
               }
           ]
       }
   }
}

HTTP Compliance

HTTP compliance is one of the basic application security violations. It validates the request itself and also prevents the use of the HTTP protocol as an entry point to the application.

In this example, we enable the HTTP compliance violation with the blocking as true. We also configure (enabled or disabled) all of its sub-violations in the relevant HTTP section. Note that you can add/remove sub-violations to match your desired configurations. However, not listing a violation does not mean it will be disabled. Rather, it would actually mean that the default configuration would not be overridden for that specific sub-violation.

{
    "name": "policy_name",
    "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
    "applicationLanguage": "utf-8",
    "enforcementMode": "blocking",
    "blocking-settings": {
        "violations": [
            {
                "name": "VIOL_HTTP_PROTOCOL",
                "alarm": true,
                "block": true
            }
        ],
        "http-protocols": [
            {
                "description": "Header name with no header value",
                "enabled": true
            },
            {
                "description": "Chunked request with Content-Length header",
                "enabled": true
            },
            {
                "description": "Check maximum number of parameters",
                "enabled": true,
                "maxParams": 5
            },
            {
                "description": "Check maximum number of headers",
                "enabled": true,
                "maxHeaders": 20
            },
            {
                "description": "Body in GET or HEAD requests",
                "enabled": true
            },
            {
                "description": "Bad multipart/form-data request parsing",
                "enabled": true
            },
            {
                "description": "Bad multipart parameters parsing",
                "enabled": true
            },
            {
                "description": "Unescaped space in URL",
                "enabled": true
            }
        ]
    }
}

Evasion Techniques

Evasion techniques refers to techniques usually used by hackers to attempt to access resources or evade what would otherwise be identified as an attack. Like HTTP compliance, evasion techniques have a list of sub-violations that can be configured for additional granularity and to reduce false positives.

In this example, we enable the evasion technique violation with the blocking as true. We also configure (enabled or disabled) all of its sub-violations in the relevant section. Note that you can add/remove sub-violations to match your desired configurations. However, not listing a violation does not mean it will be disabled. Rather, it would actually mean that the default configuration would not be overridden for that specific sub-violation.

{
    "policy": {
        "name": "evasions_enabled",
        "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "blocking-settings": {
            "violations": [
                {
                    "name": "VIOL_EVASION",
                    "alarm": true,
                    "block": true
                }
            ],
            "evasions": [
                {
                    "description": "Bad unescape",
                    "enabled": true
                },
                {
                    "description": "Directory traversals",
                    "enabled": true
                },
                {
                    "description": "Bare byte decoding",
                    "enabled": true
                },
                {
                    "description": "Apache whitespace",
                    "enabled": true
                },
                {
                    "description": "Multiple decoding",
                    "enabled": true,
                    "maxDecodingPasses": 2
                },
                {
                    "description": "IIS Unicode codepoints",
                    "enabled": true
                },
                {
                    "description": "IIS backslashes",
                    "enabled": true
                },
                {
                    "description": "%u decoding",
                    "enabled": true
                }
            ]
        }
    }
}

Attack Signatures

Attack signatures may be a little more difficult to configure as there are a number of configuration items and values in different places that may seem confusing. The first thing to be done is to enable the attack signature violation itself. Then, we need to configure which signature sets are to be enforced. Note that there are different ways to configure these sets and that there might be some overlap when doing so. You can also enable/disable signatures individually (but that would be a very exhaustive process).

In this example, we enable the attack signature violation, and specify that we want to enforce all signatures. Note that blocking setting cannot be blank.

{
    "policy": {
        "name": "attack_sigs",
        "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "signature-sets": [
            {
                "name": "All Signatures",
                "block": true,
                "alarm": true
            }
        ]
    }
}

In this example, we enable the attack signature violation, and specify that we want to enforce only high accuracy signatures.

{
    "policy": {
        "name": "attack_sigs",
        "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "signature-sets": [
            {
                "name": "High Accuracy Signatures",
                "block": true,
                "alarm": true
            }
        ]
    }
}

In this example, we exclude the signature ID 200001834.

{
    "policy": {
        "name": "signature_exclude",
        "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "signature-sets": [
            {
                "name": "All Signatures",
                "block": true,
                "alarm": true
            }
        ],
        "signatures": [
            {
                "signatureId": 200001834,
                "enabled": false
            }
        ]
    }
}

In this example, the policy is the same but a new section is added and the attack signatures to be modified are appended. We use the same signature ID 200001834:

{
    "policy": {
        "name": "signature_modification_entitytype",
        "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "signature-sets": [
            {
                "name": "All Signatures",
                "block": true,
                "alarm": true
            }
        ]
    },
    "modifications": [
        {
            "entityChanges": {
                "enabled": false
            },
            "entity": {
                "signatureId": 200001834
            },
            "entityType": "signature",
            "action": "add-or-update"
        }
    ]
}

For multiple attack signatures, the signature IDs need to be added as separate entities under the modifications list, each on its own, with only the signature ID updated:

{
    "modifications": [
        {
            "entityChanges": {
                "enabled": false
            },
            "entity": {
                "signatureId": 200001834
            },
            "entityType": "signature",
            "action": "add-or-update"
        },
        {
            "entityChanges": {
                "enabled": false
            },
            "entity": {
                "signatureId": 200004461
            },
            "entityType": "signature",
            "action": "add-or-update"
        }
    ]
}

Server Technologies

Another way to configure attack signature sets is by applying server technologies. Server technologies applies sets of signatures that would be relevant to attacks targeted to a specific OS, application, or server type. The Server Technologies are represented in attack signatures as systems using the same name, for example SharePoint. Note, however, that the overlap between Server Technologies and signature systems is not complete: there are server technologies that cannot be represented as signature systems, and also a few generic signature systems that are not represented as server technologies. The exact details will follow in the sections just below. Server technologies that are not signature systems will not bring in new signatures when added to the policy, but associating them with the policy still has declarational value, and in one of the future signature updates they may be associated with new signatures.

In this example, we enable the attack signature violation, and enabled the Apache/NCSA HTTP Server server technology, which in turn enables attack signatures specific to this type of technology. We also enabled signatures with minimum accuracy of low. This would include low, medium, and high accuracy attack signatures.

{
    "policy": {
        "name": "policy_name",
        "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "signature-settings": {
            "attackSignatureFalsePositiveMode": "disabled",
            "minimumAccuracyForAutoAddedSignatures": "low"
        },
        "server-technologies": [
            { "serverTechnologyName": "Apache/NCSA HTTP Server" }
        ]
    }
}
Available Server Technologies

The table below lists all the available Server Technologies. Some of them are built on top others on the stack and including them implies the inclusion of the latter. For example: ASP.NET implies both IIS and Microsoft Windows. This is indicated in the “implied technologies” column when applicable. We also denote the server technologies that currently have a signature system counterpart.

Server Technology Name Description Implied Technologies Signature System?
Jenkins Jenkins is an open source automation server written in Java. Jenkins helps to automate the non-human part of the software development process, with continuous integration and facilitating technical aspects of continuous delivery. It is a server-based system that runs in servlet containers such as Apache Tomcat.   Yes
SharePoint SharePoint is a web-based collaborative platform that integrates with Microsoft Office. Launched in 2001, SharePoint is primarily sold as a document management and storage system, but the product is highly configurable and usage varies substantially among organizations.   Yes
Oracle Application Server Oracle Internet Application Server provides a single integrated packaged solution of for middleware infrastructure including Oracle Containers for J2EE, Oracle Web Cache, Oracle HTTP Server, Oracle Forms, Oracle Reports, Oracle Portal and Oracle Discoverer.   Yes
Python Python is an interpreted, high-level, general-purpose programming language. Created by Guido van Rossum and first released in 1991, Python has a design philosophy that emphasizes code readability, notably using significant whitespace. It provides constructs that enable clear programming on both small and large scales.   Yes
Oracle Identity Manager Oracle Identity Manager (OIM) enables enterprises to manage the entire user life-cycle across all enterprise resources both within and beyond a firewall. Within Oracle Identity Management it provides a mechanism for implementing the user-management aspects of a corporate policy.   Yes
Spring Boot Spring Boot makes it easy to create Spring-powered, production-grade applications and services with absolute minimum fuss. It takes an opinionated view of the Spring platform so that new and existing users can quickly get to the bits they need.   Yes
CouchDB Apache CouchDB is open source database software that focuses on ease of use and having a scalable architecture.   Yes
SQLite SQLite is a relational database management system contained in a C programming library. In contrast to many other database management systems, SQLite is not a client-server database engine. Rather, it is embedded into the end program.   Yes
Handlebars Handlebars provides the power necessary to let you build semantic templates effectively with no frustration.   No
Mustache Mustache is a simple web template system.   No
Prototype Prototype takes the complexity out of client-side web programming. Built to solve real-world problems, it adds useful extensions to the browser scripting environment and provides elegant APIs around the clumsy interfaces of Ajax and the Document Object Model.   No
Zend Zend Server is a complete and certified PHP distribution stack fully maintained and supported by Zend Technologies. It ships with an updated set of advanced value-add features designed to optimize productivity, performance, scalability and reliability.   No
Redis Redis is an open-source in-memory data structure project implementing a distributed, in-memory key-value database with optional durability. Redis supports different kinds of abstract data structures, such as strings, lists, maps, sets, sorted sets, hyperloglogs, bitmaps, streams and spatial indexes.   Yes
Underscore.js Underscore.js is a JavaScript library which provides utility functions for common programming tasks. It is comparable to features provided by Prototype.js and the Ruby language, but opts for a functional programming design instead of extending object prototypes   No
Ember.js Ember.js is an open-source JavaScript web framework, based on the Model-view-viewmodel pattern. It allows developers to create scalable single-page web applications by incorporating common idioms and best practices into the framework.   No
ZURB Foundation Foundation is a responsive front-end framework. Foundation provides a responsive grid and HTML and CSS UI components, templates, and code snippets, including typography, forms, buttons, navigation and other interface elements, as well as optional functionality provided by JavaScript extensions. Foundation is maintained by ZURB and is an open source project.   No
ef.js ef.js is an elegant HTML template engine & basic framework.   No
Vue.js Vue.js is an open-source JavaScript framework for building user interfaces and single-page applications.   No
UIKit UIkit is a lightweight and modular front-end framework for developing fast and powerful web interfaces.   No
TYPO3 CMS TYPO3 is a free and open-source web content management system written in PHP. It is released under the GNU General Public License. It can run on several web servers, such as Apache or IIS, on top of many operating systems, among them Linux, Microsoft Windows, FreeBSD, macOS and OS/2.   No
RequireJS RequireJS is a JavaScript library and file loader which manages the dependencies between JavaScript files and in modular programming. It also helps to improve the speed and quality of the code.   No
React React is a JavaScript library for building user interfaces. It is maintained by Facebook and a community of individual developers and companies. React can be used as a base in the development of single-page or mobile applications.   Yes
MooTools MooTools is a lightweight, object-oriented JavaScript framework. It is released under the free, open-source MIT License.   No
Laravel Laravel is a free, open-source PHP web framework, created by Taylor Otwell and intended for the development of web applications following the model-view-controller architectural pattern and based on Symfony.   No
GraphQL GraphQL is an open-source data query and manipulation language for APIs, and a runtime for fulfilling queries with existing data. GraphQL was developed internally by Facebook in 2012 before being publicly released in 2015.   No
Google Web Toolkit Google Web Toolkit, or GWT Web Toolkit, is an open-source set of tools that allows web developers to create and maintain complex JavaScript front-end applications in Java. Other than a few native libraries, everything is Java source that can be built on any supported platform with the included GWT Ant build files.   No
Express.js Express.js, or simply Express, is a web application framework for Node.js, released as free and open-source software under the MIT License. It is designed for building web applications and APIs. It has been called the de facto standard server framework for Node.js.   No
CodeIgniter CodeIgniter is an open-source software rapid development web framework, for use in building dynamic web sites with PHP.   No
Backbone.js Backbone.js is a JavaScript library with a RESTful JSON interface and is based on the Model-view-presenter application design paradigm. Backbone is known for being lightweight, as its only hard dependency is on one JavaScript library, Underscore.js, plus jQuery for use of the full library.   No
AngularJS AngularJS is a JavaScript-based open-source front-end web application framework mainly maintained by Google and by a community of individuals and corporations to address many of the challenges encountered in developing single-page applications.   Yes
JavaScript JavaScript, often abbreviated as JS, is a high-level, interpreted programming language that conforms to the ECMAScript specification. It is a language which is also characterized as dynamic, weakly typed, prototype-based and multi-paradigm.   Yes
Nginx Nginx is a web server which can also be used as a reverse proxy, load balancer, mail proxy and HTTP cache.   Yes
Jetty Jetty is a Java HTTP (Web) server and Java Servlet container Java Servlets/JSP Yes
Joomla Joomla is a free and open-source content management system (CMS) for publishing web content. PHP Yes
JavaServer Faces (JSF) JavaServer Faces (JSF) is a Java specification for building component-based user interfaces for web applications. Java Servlets/JSP Yes
Ruby Ruby is a dynamic, reflective, object-oriented, general-purpose programming language.   Yes
MongoDB MongoDB is a free and open-source cross-platform document-oriented database program.   Yes
Django Django is a free and open-source web framework, written in Python, which follows the model-view-template (MVT) architectural pattern.   Yes
Node.js Node.js is an open-source, cross-platform JavaScript runtime environment for developing a diverse variety of tools and applications.   Yes
Citrix Citrix Systems, Inc. is an American multinational software company that provides server, application and desktop virtualization, networking, software as a service (SaaS), and cloud computing technologies.   Yes
JBoss The JBoss Enterprise Application Platform (or JBoss EAP) is a subscription-based/open-source Java EE-based application server runtime platform used for building, deploying, and hosting highly-transactional Java applications and services. Java Servlets/JSP Yes
Elasticsearch Elasticsearch is a search engine based on Lucene.   Yes
Apache Struts Apache Struts is an open-source web application framework for developing Java EE web applications. Java Servlets/JSP Yes
XML Extensible Markup Language (XML) is a markup language that defines a set of rules for encoding documents in a format that is both human-readable and machine-readable.   Yes
PostgreSQL PostgreSQL, often simply Postgres, is an object-relational database (ORDBMS) - i.e. a RDBMS, with additional (optional use) “object” features - with an emphasis on extensibility and standards-compliance.   Yes
IBM DB2 IBM DB2 contains database server products developed by IBM.   Yes
Sybase/ASE SAP ASE (Adaptive Server Enterprise), originally known as Sybase SQL Server, and also commonly known as Sybase DB or ASE, is a relational model database server product for businesses developed by Sybase Corporation which became part of SAP AG.   Yes
CGI Common Gateway Interface (CGI) offers a standard protocol for web servers to interface with executable programs running on a server that generate web pages dynamically.   Yes
Proxy Servers A proxy server is a server (a computer system or an application) that acts as an intermediary for requests from clients seeking resources from other servers.   Yes
SSI (Server Side Includes) Server Side Includes (SSI) is a simple interpreted server-side scripting language used almost exclusively for the Web.   Yes
Cisco Cisco Systems, Inc. is an American multinational corporation technology company headquartered in San Jose, California, that designs, manufactures and sells networking equipment worldwide.   Yes
Novell Novell Directory Services (NDS) is a popular software product for managing access to computer resources and keeping track of the users of a network, such as a company’s intranet, from a single point of administration.   Yes
Macromedia JRun JRun is a J2EE application server, originally developed in 1997 as a Java Servlet engine by Live Software and subsequently purchased by Allaire, who brought out the first J2EE compliant version.   Yes
BEA Systems WebLogic Server Oracle WebLogic Server is a Java EE application server currently developed by Oracle Corporation. Java Servlets/JSP Yes
Lotus Domino IBM Notes and IBM Domino are the client and server, respectively, of a collaborative client-server software platform sold by IBM.   Yes
MySQL MySQL is an open-source relational database management system (RDBMS).   Yes
Oracle Oracle Database (commonly referred to as Oracle RDBMS or simply as Oracle) is an object-relational database management system produced and marketed by Oracle Corporation.   Yes
Microsoft SQL Server Microsoft SQL Server is a relational database management system developed by Microsoft.   Yes
PHP PHP is a server-side scripting language designed primarily for web development but is also used as a general-purpose programming language.   Yes
Outlook Web Access Outlook on the web (previously called Exchange Web Connect, Outlook Web Access, and Outlook Web App in Office 365 and Exchange Server 2013) is a personal information manager web app from Microsoft. ASP.NET, IIS, Microsoft Windows Yes
Apache/NCSA HTTP Server The Apache HTTP Server, colloquially called Apache, is the world’s most used web server software.   Yes
Apache Tomcat Apache Tomcat, often referred to as Tomcat, is an open-source Java Servlet Container developed by the Apache Software Foundation (ASF). Java Servlets/JSP Yes
WordPress WordPress is a free and open-source content management system (CMS) based on PHP and MySQL. XML, PHP Yes
Macromedia ColdFusion Adobe ColdFusion is a commercial rapid web application development platform created by JJ Allaire in 1995.   Yes
Unix/Linux Unix is a family of multitasking, multiuser computer operating systems that derive from the original AT&T Unix, developed in the 1970s at the Bell Labs research center by Ken Thompson, Dennis Ritchie, and others.   Yes
Microsoft Windows Microsoft Windows (or simply Windows) is a metafamily of graphical operating systems developed, marketed, and sold by Microsoft.   Yes
ASP.NET ASP.NET is an open-source server-side web application framework designed for web development to produce dynamic web pages. IIS, Microsoft Windows Yes
Front Page Server Extensions (FPSE) FrontPage Server Extensions are a software technology that allows Microsoft FrontPage clients to communicate with web servers, and provide additional functionality intended for websites.   Yes
IIS Internet Information Services (IIS, formerly Internet Information Server) is an extensible web server created by Microsoft for use with Windows NT family. Microsoft Windows Yes
WebDAV Web Distributed Authoring and Versioning (WebDAV) is an extension of the Hypertext Transfer Protocol (HTTP) that allows clients to perform remote Web content authoring operations.   Yes
ASP Active Server Pages (ASP), later known as Classic ASP or ASP Classic, is Microsoft’s first server-side script engine for dynamically generated web pages. IIS, Microsoft Windows Yes
Java Servlets/JSP A Java servlet is a Java program that extends the capabilities of a server.   Yes
jQuery jQuery is a cross-platform JavaScript library designed to simplify the client-side scripting of HTML.   Yes
Generic Signature Systems

These signature systems are generic and do not represent a particular technology, therefore do not have a server technology counterpart. Yet, there are signatures associated with them. The Generic Detection Signatures factory singature set includes most of these signatures. You can define your own signature sets using one or more of those systems.

System Name Description
Other Web Server Web Servers that are not covered by any of the specific server technologies
System Independent Used to denote signatures that apply to any server technology
Various Systems Server-side systems not covered by any of the existing server technologies or the other systems here
Generic Database Database systems that are not covered by any of the specific server technologies

Threat Campaigns

The Threat Campaign mechanism detects attacks coming from known attack campaigns. They are based on patterns that identify the traffic from those campaigns. The mechanism is very accurate and has very low false positive rate. However it does not cover malicious traffic that is not part of those campaigns.

Just like attack signatures, the Threat Campaign patterns are updated regularly. Unlike attack signatures, the NGINX App Protect installation does not include any Threat Campaigns and you need to install the them in order for the protection to take effect. Due to the highly dynamic nature of those campaigns the updates are issued far more frequently than the attack signatures. You need to install those updates close to the time they are issued in order to get the most effective protection.

The default policy enables the mechanism with all available Threat Campaigns and blocks when detecting one. Since the risk of false positive is very low, you do not need to enable or disable specific Threat Campaigns. Rather, you can disable the whole mechanism or decide to only alarm rather than block. You can do that by modifying the properties of the Threat Campaign Violation - VIOL_THREAT_CAMPAIGN.

In this example we disable both alarm and blocking.

{
   "policy": {
       "name": "policy_name",
       "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
       "applicationLanguage": "utf-8",
       "enforcementMode": "blocking",
       "blocking-settings": {
           "violations": [
               {
                   "name": "VIOL_THREAT_CAMPAIGN",
                   "alarm": false,
                   "block": false
               }
           ]
       }
   }
}

Data Guard - Blocking

Data Guard is a security feature that can be used to prevent the leakage of sensitive information from an application. This could be credit card numbers or Social Security numbers (CCN, SSN, etc.). Once this feature is enabled, sensitive data is either blocked or masked, depending on the configuration.

In this example, we enable the data guard violation in blocking mode. In the detailed configuration, we enable enforcement of data guard and specify which items are being protected against information leakage. Note that if blocking is enabled, data masking will have no effect in this case.

{
    "policy": {
        "name": "dataguard_blocking",
        "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "blocking-settings": {
            "violations": [
                {
                    "name": "VIOL_DATA_GUARD",
                    "alarm": true,
                    "block": true
                }
            ]
        },
        "data-guard": {
            "enabled": true,
            "maskData": true,
            "creditCardNumbers": true,
            "usSocialSecurityNumbers": true,
            "enforcementMode": "ignore-urls-in-list",
            "enforcementUrls": []
        }
    }
}

Data Guard - Masking

Masking is used when we do not want to block the page entirely, but want to mask all sensitive data in the response.

In this example, we enable data guard in alarm mode. In the detailed configuration, we enable enforcement of data guard and specify which items are being protected against information leakage.

{
    "policy": {
        "name": "nginx_default_policy",
        "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "blocking-settings": {
            "violations": [
                {
                    "name": "VIOL_DATA_GUARD",
                    "alarm": true,
                    "block": false
                }
            ]
        },
        "data-guard": {
            "enabled": true,
            "maskData": true,
            "creditCardNumbers": true,
            "usSocialSecurityNumbers": true,
            "enforcementMode": "ignore-urls-in-list",
            "enforcementUrls": []
        }
    }
}

File Types

A user can enable/disable specific file types in the policy.

In this example, we enable the file type violation in blocking mode. In the detailed configuration, we allow the * wildcard entity which would allow all file types by default. In the last section, we explicitly disable the bat file type. This is an example of allowing all, but specifically blocking (via deny list) certain items. You may add as many file types as you wish, each declared in its own curly brackets, along with the "allowed": false directive.

{
    "policy": {
        "name": "policy1",
        "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "blocking-settings": {
            "violations": [
                {
                    "name": "VIOL_FILETYPE",
                    "alarm": true,
                    "block": true
                }
            ]
        },
        "filetypes": [
            {
                "name": "*",
                "type": "wildcard",
                "allowed": true,
                "checkPostDataLength": false,
                "postDataLength": 4096,
                "checkRequestLength": false,
                "requestLength": 8192,
                "checkUrlLength": true,
                "urlLength": 2048,
                "checkQueryStringLength": true,
                "queryStringLength": 2048,
                "responseCheck": false
            },
            {
                "name": "bat",
                "allowed": false
            }
        ]
    }
}

Allowed Methods

In the policy, you can specify what methods to allow or disallow.

In this example, we enable the illegal method violation in blocking mode. In the methods configuration, we define which of the methods are allowed, and how they will be treated in terms of flow. Note that the “act as” does not imply enforcement on the method as the “act as”.

{
    "policy": {
        "name": "blocking_policy",
        "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "blocking-settings": {
            "violations": [
                {
                    "name": "VIOL_METHOD",
                    "alarm": true,
                    "block": true
                }
            ]
        },
        "methods": [
            {
                "name": "GET"
            },
            {
                "name": "POST"
            },
            {
                "name": "HEAD"
            },
            {
                "name": "PUT"
            },
            {
                "name": "PATCH"
            },
            {
                "name": "DELETE"
            },
            {
                "name": "OPTIONS"
            }
        ]
    }
}

Response Codes

Response codes are a general setting that defines which response codes are acceptable, while all others will be blocked.

In this example, we enable the response status codes violation in blocking mode. In the general configuration, we define which of the response codes are allowed. This would mean that all others will be considered as illegal response codes and will be blocked. In this configuration, you specify a list of comma-separated response codes that are allowed.

{
    "policy": {
        "name": "allowed_response",
        "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "blocking-settings": {
            "violations": [
                {
                    "name": "VIOL_HTTP_RESPONSE_STATUS",
                    "alarm": true,
                    "block": true
                }
            ]
        },
        "general": {
            "allowedResponseCodes": [
                400,
                401,
                403,
                404,
                502,
                499
            ]
        }
    }
}

Parameters

When configuring handling of parameters, it is a bit different from other configurations we have dealt with earlier, where we enable a violation and configure its details. With parameters, there are a number of independent violations that need to be enabled on their own, as well as a parameter section to define further customization. The full list of parameter violations can be extracted from the above violation list.

{
    "policy": {
        "name": "parameters_blocking",
        "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "blocking-settings": {
            "violations": [
                {
                    "name": "VIOL_PARAMETER_MULTIPART_NULL_VALUE",
                    "alarm": true,
                    "block": true
                },
                {
                    "name": "VIOL_PARAMETER_NAME_METACHAR",
                    "alarm": true,
                    "block": true
                },
                {
                    "name": "VIOL_PARAMETER_VALUE_METACHAR",
                    "alarm": true,
                    "block": true
                }
            ]
        },
        "parameters": [
            {
                "checkMetachars": true,
                "parameterLocation": "any",
                "valueType": "auto-detect",
                "metacharsOnParameterValueCheck": true,
                "name": "*",
                "type": "wildcard",
            }
        ]
    }
}

In this example we configure allowed meta-characters in parameter name and value.

{
    "policy": {
        "name": "parameters_allowed_metachars",
        "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "blocking-settings": {
            "violations": [
                {
                    "name": "VIOL_PARAMETER_MULTIPART_NULL_VALUE",
                    "alarm": true,
                    "block": true
                },
                {
                    "name": "VIOL_PARAMETER_NAME_METACHAR",
                    "alarm": true,
                    "block": true
                },
                {
                    "name": "VIOL_PARAMETER_VALUE_METACHAR",
                    "alarm": true,
                    "block": true
                }
            ]
        },
        "parameters": [
            {
                "checkMetachars": true,
                "sensitiveParameter": false,
                "parameterLocation": "any",
                "valueType": "auto-detect",
                "nameMetacharOverrides": [
                    {
                        "isAllowed": true,
                        "metachar": "0x3c"
                    },
                    {
                        "isAllowed": true,
                        "metachar": "0x3e"
                    }
                ],
                "metacharsOnParameterValueCheck": true,
                "allowEmptyValue": true,
                "checkMaxValueLength": false,
                "valueMetacharOverrides": [
                    {
                        "isAllowed": true,
                        "metachar": "0x3c"
                    },
                    {
                        "isAllowed": true,
                        "metachar": "0x3e"
                    }
                ],
                "name": "*",
                "level": "global",
                "allowRepeatedParameterName": true,
                "attackSignaturesCheck": true,
                "signatureOverrides": [],
                "type": "wildcard",
            }
        ]
    }
}

In this example, we define a sensitive parameter “mypass” configuration.

{
    "policy": {
        "name": "parameters_sensitive",
        "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "blocking-settings": {
            "violations": [
                {
                    "name": "VIOL_PARAMETER_MULTIPART_NULL_VALUE",
                    "alarm": true,
                    "block": false
                },
                {
                    "name": "VIOL_PARAMETER_NAME_METACHAR",
                    "alarm": true,
                    "block": false
                },
                {
                    "name": "VIOL_PARAMETER_VALUE_METACHAR",
                    "alarm": true,
                    "block": false
                }
            ]
        },
        "sensitive-parameters": [
            {
                "name": "mypass"
            }
        ]
    }
}

User-Defined URLs

The user-defined URL feature allows the user to configure the URL while supporting the following options:

  • Define a protected URL configuration both explicitly and by wildcards.
  • Define a per-URL list of allowed/disallowed methods that will override the list defined in the policy level.
  • Define a content-type: json/xml/form-data on a user-defined url.
  • Define an Allowed/Disallowed user-defined URL.
  • Add a user-defined URL to the Signature/Metacharacters override list.

In this example we configure allowed meta-characters in a user-defined URL:

{
    "policy": {
        "name": "/Common/user_defined_URL",
        "template": {
            "name": "POLICY_TEMPLATE_NGINX_BASE"
        },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "blocking-settings": {
            "violations": [
                {
                    "name": "VIOL_URL",
                    "alarm": true,
                    "block": true
                },
                {
                    "name": "VIOL_URL_METACHAR",
                    "alarm": true,
                    "block": true
                }
            ]
        },
        "urls": [
            {
                "method": "*",
                "name": "/meta*",
                "protocol": "http",
                "type": "wildcard",
                "metacharsOnUrlCheck": true,
                "metacharOverrides": [
                    {
                        "isAllowed": true,
                        "metachar": "0x3c"
                    },
                    {
                        "isAllowed": false,
                        "metachar": "0x28"
                    }
                ],
                "wildcardOrder": 2
            }
        ]
    }
}

In this example we configure allowed signatures in a user-defined URL:

{
    "policy": {
        "name": "/Common/user_defined_URL",
        "template": {
            "name": "POLICY_TEMPLATE_NGINX_BASE"
        },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "blocking-settings": {
            "violations": [
                {
                    "name": "VIOL_URL",
                    "alarm": true,
                    "block": true
                }
            ]
        },
        "urls": [
            {
                "method": "*",
                "name": "/test*",
                "protocol": "http",
                "type": "wildcard",
                "wildcardOrder": 1,
                "attackSignaturesCheck": true,
                "signatureOverrides": [
                    {
                        "enabled": true,
                        "signatureId": 200010008
                    }
                ]
            }
        ]
    }
}

In this example, we configure Wildcard/Explicit URLs, where the first URL is permitted for all methods, and the second is permitted only for GET:

{
    "policy": {
        "name": "/Common/user_defined_URL",
        "template": {
            "name": "POLICY_TEMPLATE_NGINX_BASE"
        },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "blocking-settings": {
            "violations": [
                {
                    "name": "VIOL_URL",
                    "alarm": true,
                    "block": true
                }
            ]
        },
        "urls": [
            {
                "method": "*",
                "name": "/test*",
                "protocol": "http",
                "type": "wildcard",
                "wildcardOrder": 1
            },
            {
                "method": "GET",
                "name": "/index.html",
                "protocol": "http",
                "type": "explicit"
            }
        ]
    }
}

In this example, we configure json/xml/form-data content types for a specific user-defined URL:

{
    "policy": {
        "name": "/Common/user_defined_URL",
        "template": {
            "name": "POLICY_TEMPLATE_NGINX_BASE"
        },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "blocking-settings": {
            "violations": [
                {
                    "name": "VIOL_URL",
                    "alarm": true,
                    "block": true
                },
                {
                    "name": "VIOL_METHOD",
                    "alarm": true,
                    "block": true
                },
                {
                    "name": "VIOL_JSON_MALFORMED",
                    "alarm": true,
                    "block": true
                },
                {
                    "name": "VIOL_JSON_FORMAT",
                    "alarm": true,
                    "block": true
                },
                {
                    "name": "VIOL_XML_FORMAT",
                    "alarm": true,
                    "block": true
                }
            ]
        },
        "json-profiles": [
            {
                "name": "Default",
                "handleJsonValuesAsParameters": false,
                "defenseAttributes": {
                    "maximumTotalLengthOfJSONData": "any",
                    "maximumArrayLength": "any",
                    "maximumStructureDepth": "any",
                    "maximumValueLength": "any"
                }
            }
        ],
        "xml-profiles": [
            {
                "name": "Default",
                "defenseAttributes": {
                    "maximumAttributesPerElement": "any",
                    "maximumDocumentDepth": "any",
                    "maximumAttributeValueLength": "any",
                    "maximumChildrenPerElement": "any",
                    "maximumDocumentSize": "any",
                    "maximumElements": "any",
                    "maximumNameLength": "any",
                    "maximumNSDeclarations": "any",
                    "maximumNamespaceLength": "any",
                    "tolerateLeadingWhiteSpace": true,
                    "tolerateCloseTagShorthand": true,
                    "allowCDATA": true,
                    "allowExternalReferences": true,
                    "allowProcessingInstructions": true
                }
            }
        ],
        "urls": [
            {
                "method": "*",
                "name": "/first*",
                "protocol": "http",
                "type": "wildcard",
                "wildcardOrder": 1,
                "urlContentProfiles": [
                    {
                        "headerValue": "*",
                        "headerName": "*",
                        "headerOrder": "3",
                        "type": "form-data"
                    },
                    {
                        "contentProfile": {
                            "name": "Default"
                        },
                        "headerValue": "*xml*",
                        "headerName": "Content-Type",
                        "headerOrder": "2",
                        "type": "xml"
                    },
                    {
                        "contentProfile": {
                            "name": "Default"
                        },
                        "headerValue": "*json*",
                        "headerName": "Content-Type",
                        "headerOrder": "1",
                        "type": "json"
                    }
                ]
            }
        ]
    }
}

User-Defined Parameters

So far, we have been managing the default parameter or * entity. What if we want to give specific attributes to specific parameters? This can be done by creating and configuring the user-defined parameters. This feature gives the user full control over what the parameter should include, where it should be located and allows for granularity in configuring each and every parameter. Here you can:

  • Create unique parameters and specify attributes for each.
  • Define what data type the parameter should contain.
  • Define the allowed location where you expect to see a parameter.
  • Define minimum/maximum values and minimum/maximum lengths for a parameter.
  • Define whether a parameter is mandatory or not.
  • Define whether the parameter can have empty values or not.
  • Define whether to inspect a parameter for violations, attack signatures, or meta-characters.
  • Decide whether to exclude certain violations, attack signatures, or meta-characters for a parameter.

In the following example, we configure a parameter that takes text as a user input and is limited in length. Please also note the violations that we enable to block any request that does not follow our configuration. The text parameter takes string values (here configured as alpha-numeric), and the length of the allowed string is between 4 and 8 characters. Any string below or above these values will trigger the violation VIOL_PARAMETER_VALUE_LENGTH.

{
    "policy": {
        "name": "user_defined_parameters_data_types",
        "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "blocking-settings": {
            "violations": [
                {
                    "name": "VIOL_PARAMETER_NUMERIC_VALUE",
                    "alarm": true,
                    "block": true
                },
                {
                    "name": "VIOL_PARAMETER_VALUE_LENGTH",
                    "alarm": true,
                    "block": true
                },
                {
                    "name": "VIOL_PARAMETER_STATIC_VALUE",
                    "alarm": true,
                    "block": true
                },
                {
                    "name": "VIOL_PARAMETER_DATA_TYPE",
                    "alarm": true,
                    "block": true
                }
            ]
        },
        "parameters": [
            {
                "name": "text",
                "type": "explicit",
                "parameterLocation": "any",
                "mandatory": false,
                "allowEmptyValue": false,
                "allowRepeatedParameterName": false,
                "sensitiveParameter": false,
                "valueType": "user-input",
                "dataType": "alpha-numeric",
                "checkMinValueLength": true,
                "checkMaxValueLength": true,
                "minimumLength": 4,
                "maximumLength": 8
            }
        ]
    }
}

In the next example, we configure a numeric parameter. This parameter accepts only integer values and allows values between 9 and 99 (non-inclusive). If the request includes anything other than an integer, it will trigger the VIOL_PARAMETER_DATA_TYPE violation. If the parameter value falls beyond or below the desired values, it will trigger the VIOL_PARAMETER_NUMERIC_VALUE violation. Please note that if you change the values of exclusiveMin and exclusiveMax to false, values equal to the boundary values will be accepted (namely 9 and 99).

{
    "policy": {
        "name": "user_defined_parameters_data_types",
        "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "blocking-settings": {
            "violations": [
                {
                    "name": "VIOL_PARAMETER_NUMERIC_VALUE",
                    "alarm": true,
                    "block": true
                },
                {
                    "name": "VIOL_PARAMETER_VALUE_LENGTH",
                    "alarm": true,
                    "block": true
                },
                {
                    "name": "VIOL_PARAMETER_STATIC_VALUE",
                    "alarm": true,
                    "block": true
                },
                {
                    "name": "VIOL_PARAMETER_DATA_TYPE",
                    "alarm": true,
                    "block": true
                }
            ]
        },
        "parameters": [
            {
                "name": "number",
                "type": "explicit",
                "parameterLocation": "any",
                "mandatory": false,
                "allowEmptyValue": false,
                "allowRepeatedParameterName": false,
                "sensitiveParameter": false,
                "valueType": "user-input",
                "dataType": "integer",
                "checkMinValue": true,
                "checkMaxValue": true,
                "minimumValue": 9,
                "maximumValue": 99,
                "exclusiveMin": true,
                "exclusiveMax": true
            }
        ]
    }
}

For increased granularity, you can configure whether the parameter value is also a multiple of a specific number. This is useful when you wish to limit the input to specific values. The following example configures a parameter that accepts values in the range of 0 to 10 and are only multiples of 3. This means that the accepted values are 3, 6 and 9. Any other value will trigger the VIOL_PARAMETER_NUMERIC_VALUE violation.

{
    "policy": {
        "name": "user_defined_parameters_data_types",
        "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "blocking-settings": {
            "violations": [
                {
                    "name": "VIOL_PARAMETER_NUMERIC_VALUE",
                    "alarm": true,
                    "block": true
                },
                {
                    "name": "VIOL_PARAMETER_VALUE_LENGTH",
                    "alarm": true,
                    "block": true
                },
                {
                    "name": "VIOL_PARAMETER_STATIC_VALUE",
                    "alarm": true,
                    "block": true
                },
                {
                    "name": "VIOL_PARAMETER_DATA_TYPE",
                    "alarm": true,
                    "block": true
                }
            ]
        },
        "parameters": [
            {
                "name": "multiples",
                "type": "explicit",
                "parameterLocation": "any",
                "mandatory": false,
                "allowEmptyValue": false,
                "allowRepeatedParameterName": false,
                "sensitiveParameter": false,
                "valueType": "user-input",
                "dataType": "integer",
                "checkMinValue": true,
                "checkMaxValue": true,
                "minimumValue": 0,
                "maximumValue": 10,
                "checkMultipleOfValue": true,
                "multipleOf": 3
            }
        ]
    }
}

Another very useful example is when the user wants to limit the parameter to a single context, like in a header or a query string. If the same variable appears in a different location, it will trigger the VIOL_PARAMETER_LOCATION violation.

{
    "policy": {
        "name": "user_defined_parameters_misc_test",
        "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "blocking-settings": {
            "violations": [
                {
                    "name": "VIOL_PARAMETER_NUMERIC_VALUE",
                    "alarm": true,
                    "block": true
                },
                {
                    "name": "VIOL_PARAMETER_VALUE_LENGTH",
                    "alarm": true,
                    "block": true
                },
                {
                    "name": "VIOL_PARAMETER_STATIC_VALUE",
                    "alarm": true,
                    "block": true
                },
                {
                    "name": "VIOL_PARAMETER_DATA_TYPE",
                    "alarm": true,
                    "block": true
                },
                {
                    "name": "VIOL_PARAMETER_LOCATION",
                    "alarm": true,
                    "block": true
                }
            ]
        },
        "parameters": [
            {
                "name": "headerparam",
                "type": "explicit",
                "parameterLocation": "header",
                "mandatory": false,
                "allowEmptyValue": false,
                "allowRepeatedParameterName": false,
                "sensitiveParameter": false,
                "valueType": "user-input",
                "dataType": "alpha-numeric",
                "checkMinValueLength": false,
                "checkMaxValueLength": false
            }
        ]
    }
}

Another very useful example is the following configuration. It has:

  • A sensitive parameter mypass that should be masked in the logs.
  • A parameter empty that is allowed to be empty.
  • A parameter repeated that can be repeated multiple times.
  • A parameter mandatory that is mandatory for all requests.

Please note that new violations were enabled so that the configuration becomes effective.

{
    "policy": {
        "name": "user_defined_parameters_misc_test",
        "template": {
            "name": "POLICY_TEMPLATE_NGINX_BASE"
        },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "blocking-settings": {
            "violations": [
                {
                    "name": "VIOL_PARAMETER_EMPTY_VALUE",
                    "alarm": true,
                    "block": true
                },
                {
                    "name": "VIOL_PARAMETER_REPEATED",
                    "alarm": true,
                    "block": true
                },
                {
                    "name": "VIOL_MANDATORY_PARAMETER",
                    "alarm": true,
                    "block": true
                },
                {
                    "name": "VIOL_PARAMETER",
                    "alarm": true,
                    "block": true
                }
            ]
        },
        "parameters": [
            {
                "name": "mypass",
                "type": "explicit",
                "parameterLocation": "any",
                "sensitiveParameter": true,
                "valueType": "auto-detect"
            },
            {
                "name": "empty",
                "type": "explicit",
                "parameterLocation": "any",
                "mandatory": false,
                "allowEmptyValue": true,
                "allowRepeatedParameterName": false,
                "sensitiveParameter": false,
                "valueType": "auto-detect"
            },
            {
                "name": "repeated",
                "type": "explicit",
                "parameterLocation": "any",
                "mandatory": false,
                "allowEmptyValue": false,
                "allowRepeatedParameterName": true,
                "sensitiveParameter": false,
                "valueType": "auto-detect"
            },
            {
                "name": "mandatory",
                "type": "explicit",
                "parameterLocation": "any",
                "mandatory": true,
                "allowEmptyValue": false,
                "allowRepeatedParameterName": false,
                "sensitiveParameter": false,
                "valueType": "auto-detect"
            }
        ]
    }
}

User-Defined Signatures

Another useful expansion to the customization capabilities is the ability to create user-defined signatures. This capability allows the user to define new signatures, configure how they behave in terms of enforcement, and categorize them in user-defined signature sets (using tags) for ease of management.

The process of creating and implementing a user policy that contains user-defined signatures is a three-fold process:

  • Creating the user-defined signature definitions in separate JSON files.
  • Adding the relevant references (names, tags, signature sets) to the user-defined signatures in the policy file.
  • Adding the definitions and referencing the relevant policy file in the nginx.conf file.
User-Defined Signature Definitions

The user-defined signature definition file is a JSON file where the signatures themselves are defined and given their properties and tags. The format of the user-defined signature definition is as follows:

{
    "tag": "tag_name",
    "revisionDatetime": "2020-01-21T18:32:02Z",
    "signatures": []
}

Tags help organizing the user-defined signatures in bundles so that all signatures in that bundle are (usually) authored by the same person and share a common purpose or set of applications that will consume it. It also creates name spaces that avoid name conflicts among user-defined signatures. Signatures are uniquely identified by the combination of tag and name. The tag_name should be replaced with the tag name to be assigned to all signatures in this file or group. The revisionDatetime specifies the date or version of the signature file. Please note that you can create as many user-defined signature definition files as you wish provided that you assign a unique tag for each file and that the user-defined signatures have unique names, both within the same file, or across different files.

To add user-defined signatures to the signatures list, each signature must have the following format:

{
    "name": "unique_name",
    "description": "Add your description here",
    "rule": "content:\"string\"; nocase;",
    "signatureType": "request",
    "attackType": {
        "name": "Brute Force Attack"
    },
    "systems": [
        {
            "name": "Microsoft Windows"
        },
        {
            "name": "Unix/Linux"
        }
    ],
    "risk": "medium",
    "accuracy": "medium"
}

Here is a brief explanation about each of the above items in the signature definition:

  • name - is the unique name to be given to the user-defined signature.
  • description - is an optional item where you can add a human-readable text to describe the functionality or purpose of the signature.
  • rule - is the rule by which the enforcement will be done. The rule uses Snort syntax: a keyword to look for in a certain context, such as URL, header, parameter, content, and optionally one or more regular expressions. For full details on how to create a rule and the possible permutations, please check the Rule Syntax page.
  • signatureType - defines whether the signature is relevant to the request or the response.
  • attackType - this field gives an indication of the attack type the signature is intended to prevent. This field is mostly useful for signature set enforcement and logging purposes. A full list of the avaiable attacks types can be found in the Attack Types section.
  • systems - is a list of systems (operating systems, programming languages, etc.) that the signature should be applicable for. Please note that systems have the same meaning and use as server technologies although the overlap between both terms is not perfect. This is explained in the above section Server Technologies.
  • risk - defines the risk level associated with this signature. Possible values are: low, medium, high.
  • accuracy - defines the accuracy level of the signature. Please note that the value of this field contributes to the value of the Violation Rating. Possible values are: low, medium, high.

The following is an example of a user-defined signature definition file called user_defined_signature_definitions.json:

{
    "softwareVersion": "15.1.0",
    "tag": "Fruits",
    "revisionDatetime": "2020-01-22T18:32:02Z",
    "signatures": [
        {
            "name": "Apple_medium_acc",
            "rule": "content:\"apple\"; nocase;",
            "signatureType": "request",
            "attackType": {
                "name": "Brute Force Attack"
            },
            "systems": [
                {
                    "name": "Microsoft Windows"
                },
                {
                    "name": "Unix/Linux"
                }
            ],
            "risk": "medium",
            "accuracy": "medium",
            "description": "Medium accuracy user defined signature with tag (Fruits)"
        }
    ]
}
Updating the Policy

Once all the user-defined signatures are added to definitions files, it is time to activate and use them in the policy. To achieve this, certain items need to be added to the policy file to enable these signatures, and to specify the action to take when they are matched. The following policy shows a simplified policy file example called user_defined_signatures_policy.json:

{
    "policy": {
        "name": "user_defined_single_signature",
        "template": {
            "name": "POLICY_TEMPLATE_NGINX_BASE"
        },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "signature-requirements": [
            {
                "tag": "Fruits",
                "minRevisionDatetime": "2020-01-20T18:32:02Z",
                "maxRevisionDatetime": "2020-01-23T18:32:02Z"
            }
        ],
        "signatures": [
            {
                "name": "Apple_medium_acc",
                "tag": "Fruits"
            }
        ],
        "signature-sets": [
            {
                "name": "Fruit_signature_set",
                "block": true,
                "alarm": true,
                "signatureSet": {
                    "filter": {
                        "tagValue": "Fruits",
                        "tagFilter": "eq"
                    }
                }
            }
        ]
    }
}

Following is an explanation of each of the items added to the bare policy that are relevant to user-defined signatures:

  • signature-requirements - Specifies which tags are being used in this policy, and from which revision/version (minRevisionDatetime and maxRevisionDatetime are optional). The signature requirements serve as an indication of what tags and revisions are required for the proper operation of the policy. If the requirement is met and the tag exists, this means that the signature import was successful and that the policy compilation process will pass. However, if the tag/revision requirement is specified and no such tag or revision exists, then the policy compilation process will fail. This could mean that the user imported the wrong definitions file, imported a different revision than the one we require, or even forgot to import the definitions file altogether.
  • signatures - The list of signatures we want to add to the policy. Please note that each signature should have its unique name added as well as its relevant tag. The signature will then be automatically enabled. This section is redundant if the user wants to enable all signatures. However, if they want to disable specific signature(s), this section becomes mandatory where each signature should have the enabled: with true or false specified. A better way to disable signatures is by removing them from the definitions file altogether and reloading the policy.
  • signature-sets - How the signatures are added to the policy enforcement. The set filters the signatures by tag and adds all the signatures matching this tag to the user-defined signature set. Here we can specify the action taken when a signature match is made (whether to alarm, block, or both)
Updating nginx.conf

In order for NGINX App Protect to load the new user-defined signatures, the user needs to add the directive: app_protect_user_defined_signatures. This directive can only be used (multiple times, if needed) in the http context in the nginx.conf file, and cannot be used under the server or location contexts. This directive accepts the path of the user-defined signature definition file as an argument. To add multiple definition files, the user will need to add a directive per file. Please note that if the file or directory is not accessible by the nginx user, an error message will be displayed, and the policy will fail to compile.

An example configuration file is listed below:

user nginx;
worker_processes  4;

load_module modules/ngx_http_app_protect_module.so;

error_log /var/log/nginx/error.log debug;
working_directory /tmp/cores;
worker_rlimit_core 1000M;

events {
    worker_connections  65536;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    app_protect_enable on;
    app_protect_policy_file "/etc/nginx/user_defined_signatures_policy.json";
    app_protect_user_defined_signatures "/etc/nginx/user_defined_signature_definitions.json";

    app_protect_security_log_enable on;
    app_protect_security_log "/etc/nginx/log-default.json" syslog:server=127.0.0.1:515;

    server {
        listen       80;
        server_name  localhost;
        proxy_http_version 1.1;

        location / {
            client_max_body_size 0;
            default_type text/html;
            proxy_pass http://127.0.0.1:8080$request_uri;
        }
    }
}

User-Defined Signature Sets

NGINX App Protect comes with pre-defined signatures and signature sets. Also, the user can create their own user-defined signatures (as we have seen above) as well as user-defined signature sets. User-defined Signature sets are suitable for organizing the sheer number of pre-defined and user-defined signatures into logical sets for better use in the policy. For pre-defined signatures, there are two ways of managing signature sets: manual addition of signatures using the signature unique IDs, or filtering signatures based on specific criteria, like request/response, risk level, accuracy level, attack type, systems, etc. For the user-defined signatures, signature IDs are automatically generated, and they cannot be used in manual addition of signatures. Therefore, only one way is possible: filtering based on tag, request/response, risk level, accuracy level, attack type, systems, etc.

The following example shows the creation of a new signature set based on filtering all signatures that have accuracy equals to “low”:

{
    "name": "filtered_signature_sets",
    "template": {
        "name": "POLICY_TEMPLATE_NGINX_BASE"
    },
    "applicationLanguage": "utf-8",
    "enforcementMode": "blocking",
    "signature-sets": [
        {
            "name": "my-low-accuracy-signatures",
            "block": true,
            "alarm": true,
            "signatureSet": {
                "type": "filter-based",
                "filter": {
                    "attackType": {
                        "name": "Other Application Attacks"
                    },
                    "signatureType": "request",
                    "riskFilter": "eq",
                    "riskValue": "high",
                    "accuracyFilter": "le",
                    "accuracyValue": "high"
                }
            }
        }
    ]
}

Please note that the filter can have one of the following values:

  • eq - Include values equal to.
  • le - Include values less than or equal.
  • ge - Include values greater than or equal.
  • all - Do not filter, use all items. Please note that all is the default value so if the user does not specify a filter, it will be considered as all. Also, if the user specifies the all filter, there is no need to specify the corresponding value element.

Therefore, the above example can be interpreted as: include all the signatures with risk equal to “high” and all signatures with accuracy equal to or less than medium. The result should include all low and medium accuracy signatures that have a high risk value.

In the following example, we demonstrate how to add signatures manually to a signature set by specifying the signature ID of each of the signatures:

{
    "name": "manual_signature_sets",
    "template": {
        "name": "POLICY_TEMPLATE_NGINX_BASE"
    },
    "applicationLanguage": "utf-8",
    "enforcementMode": "blocking",
    "signature-sets": [
        {
            "name": "my-cherry-picked-signatures",
            "block": true,
            "alarm": true,
            "signatureSet": {
                "type": "manual",
                "signatures": [
                    {
                        "signatureId": 200003360
                    },
                    {
                        "signatureId": 200001234
                    }
                ]
            }
        }
    ]
}

It is worthy to note that if a newly added signature set name matches an existing signature set name, it will not overwrite the existing set. Instead, a new set will be created with “_2” appended to the signature set name. For example, if we create a signature set with the name “My_custom_signatures” with 3 signatures, then add a new signature to the set and reload the nginx process, a new signature set will be created with the name “My_custom_signatures_2” containing the new list of 4 signatures. The older list “My_custom_signatures” with 3 signatures will remain intact.

Deny and Allow Lists

It is possible to define IP addresses or ranges that will be allowed or denied despite the rest of the configuration settings in the policy.

In this example, we use the default configuration while enabling the deny list violation. In the configuration section, we define:

  • An allowed IP 1.1.1.1
  • A denied IP 2.2.2.2
  • An allowed range of IPs 3.3.3.0/24
{
    "policy": {
        "name": "allow_deny",
        "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "blocking-settings": {
            "violations": [
                {
                    "name": "VIOL_BLACKLISTED_IP",
                    "alarm": true,
                    "block": true
                }
            ]
        },
        "whitelist-ips": [
            {
                "blockRequests": "never",
                "neverLogRequests": false,
                "ipAddress": "1.1.1.1",
                "ipMask": "255.255.255.255"
            },
            {
                "blockRequests": "always",
                "ipAddress": "2.2.2.2",
                "ipMask": "255.255.255.255"
            },
            {
                "blockRequests": "never",
                "neverLogRequests": false,
                "ipAddress": "3.3.3.0",
                "ipMask": "255.255.255.0"
            }
        ]
    }
}

Handling XML and JSON Content

XML and JSON Content Profiles

By default every request with a Content-Type header containing XML or JSON is expected to have an XML or JSON body, respectively. Consequently, a series of checks are performed to ensure that the body is indeed well-formed as XML or JSON, and certain restrictions are enforced on the size and content of that body. These restrictions are specified in XML and JSON profiles. These configuration structures are associated with URLs and optionally also with Parameters, in case parameters that are known to have XML or JSON values are defined. One of the most powerful restrictions in a JSON profile is enforcing a schema with which the content must comply. This will be detailed in the next section.

The default Base template comes with default JSON and XML profiles, both called “default”. They are associated to the * URL based on the values of the Content-Type header as described above. You can use those profiles on other URLs or Parameters in your policies, and you can also create your own custom JSON and XML profiles to customize the checks that you want on your content.

Let’s assume you have a JSON registration form under the URL /register. It is a small form, and it makes sense to limit its size to 1000 characters and its nesting depth to 2. Here is a policy that enforces this:

{
    "policy": {
        "name": "json_form_policy",
        "template": {
            "name": "POLICY_TEMPLATE_NGINX_BASE"
        },
        "json-profiles": [
            {
                "name": "reg_form_prof",
                "defenseAttributes": {
                    "maximumArrayLength": "any",
                    "maximumStructureDepth": 2,
                    "maximumTotalLengthOfJSONData": 1000,
                    "maximumValueLength": "any",
                    "tolerateJSONParsingWarnings": false
                }
            }
        ],
        "urls": [
            {
                "name": "/register",
                "method": "POST",
                "type": "explicit",
                "attackSignaturesCheck": true,
                "clickjackingProtection": false,
                "disallowFileUploadOfExecutables": false,
                "isAllowed": true,
                "mandatoryBody": false,
                "methodsOverrideOnUrlCheck": false,
                "urlContentProfiles": [
                    {
                        "headerName": "*",
                        "headerValue": "*",
                        "headerOrder": "default",
                        "type": "json",
                        "contentProfile": {
                            "name": "reg_form_prof"
                        }
                    }
                ]
            }
        ]
    }
}

The enforcement on the JSON payload is defined in the reg_form_prof JSON profile. This profile is attached to the /register URL. Note JSON content is always expected for this URL - it applies to all header name and value combinations, and no other content option exists for this URL. Also note that we limited the method to POST in this URL. A POST request to this URL with a body that is not well-formed JSON will trigger the VIOL_JSON_MALFORMED violation.

If the body of the request is legal JSON, but violates any of the restrictions in the reg_form_prof JSON profile, for example has a nesting depth of 3, then you should expect the VIOL_JSON_FORMAT violation with details on what exactly was wrong with the JSON payload.

Note: Defining a JSON or XML profile in a policy has no effect until you assign it to a URL or Parameter you defined in that policy. Profiles can be shared by more than one URL and/or Parameter.

Applying a JSON Schema

If a schema for the JSON payload exists, it can be attached to the JSON profile and App Protect will enforce it along with the other restrictions.

Here is a sample JSON schema for a registration form. It contains personal details:

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "title": "Person",
    "type": "object",
    "properties": {
        "firstName": {
            "type": "string",
            "description": "The person's first name."
        },
        "lastName": {
            "type": "string",
            "description": "The person's last name."
        },
        "age": {
            "description": "Age in years which must be equal to or greater than zero.",
            "type": "integer",
            "minimum": 0
        }
    }
}

Embedding it into the reg_form_prof JSON profile should be done in the following way:

  • Add an object containing the JSON schema to the json-validation-files array, which details all the available JSON schema validation files available in the profile. A unique fileName should be specified, and the escaped contents of the JSON schema added via the contents keyword.
  • Associate the specific JSON schema to the reg_form_prof JSON profile by adding a validationFiles array object, and set the fileName in the jsonValidationFile object to the JSON schema fileName.
  • All JSON schema files including external references must be added in this way to both the json-validation-files array, and associated with the JSON profile. The isPrimary should be set on the object containing the primary JSON schema.

This yields the following policy:

{
    "policy": {
        "name": "json_form_policy_inline_schema",
        "template": {
            "name": "POLICY_TEMPLATE_NGINX_BASE"
        },
        "json-validation-files": [
            {
                "fileName": "person_schema.json",
                "contents": "{\r\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\r\n  \"title\": \"Person\",\r\n  \"type\": \"object\",\r\n  \"properties\": {\r\n    \"firstName\": {\r\n      \"type\": \"string\",\r\n      \"description\": \"The person's first name.\"\r\n    },\r\n    \"lastName\": {\r\n      \"type\": \"string\",\r\n      \"description\": \"The person's last name.\"\r\n    },\r\n    \"age\": {\r\n      \"description\": \"Age in years which must be equal to or greater than zero.\",\r\n      \"type\": \"integer\",\r\n      \"minimum\": 0\r\n    }\r\n  }\r\n}"
            }
        ],
        "json-profiles": [
            {
                "name": "reg_form_prof",
                "defenseAttributes": {
                    "maximumArrayLength": "any",
                    "maximumStructureDepth": "any",
                    "maximumTotalLengthOfJSONData": 1000,
                    "maximumValueLength": "any",
                    "tolerateJSONParsingWarnings": false
                },
                "validationFiles": [
                    {
                        "isPrimary": true,
                        "jsonValidationFile": {
                            "fileName": "person_schema.json"
                        }
                    }
                ]
            }
        ],
        "urls": [
            {
                "name": "/register",
                "type": "explicit",
                "method": "POST",
                "attackSignaturesCheck": true,
                "clickjackingProtection": false,
                "disallowFileUploadOfExecutables": false,
                "isAllowed": true,
                "mandatoryBody": false,
                "methodsOverrideOnUrlCheck": false,
                "urlContentProfiles": [
                    {
                        "contentProfile": {
                            "name": "reg_form_prof"
                        },
                        "headerName": "*",
                        "headerOrder": "default",
                        "headerValue": "*",
                        "type": "json"
                    }
                ]
            }
        ]
    }
}

When a request to the /register URL is POST-ed with JSON content that does not comply with the above schema, the VIOL_JSON_SCHEMA violation is triggered. In the default base template, the alarm flag is turned on for this violation and if it is triggered, it affects Violation Rating. In addition, you can turn on the block flag so that this violation will also block when triggered.

Notes:

  • The schema file is embedded as a quoted string, therefore you must escape the quotes inside the schema itself.
  • We removed the nesting depth check in the JSON profile because it is enforced by the schema. It is not an error to leave the sizing checks together with the schema enforcement, but usually the schema has more accurate restrictions and leaving the profile restriction might be redundant in the best case or cause false positives in the worst.

Including an External JSON Schema File

Schema files are often developed as part of the application, independently from the App Protect Policy. It is often desirable to keep it in a separate file and reference it from the policy using a URL. Just as in all externally referenced policy sections, the JSON schema file can reside either in the NGINX file system (the default directory /etc/app_protect/conf is assumed if only the filename is specified in the file: URL, that is: file:///my_schema.json refers to the file located at /etc/app_protect/conf/my_schema.json), or on a remote Web server, typically, your source control system.

In this example the file is in the default directory:

{
    "policy": {
        "name": "json_form_policy_external_schema",
        "template": {
            "name": "POLICY_TEMPLATE_NGINX_BASE"
        },
        "json-validation-files": [
            {
                "fileName": "person_schema.json",
                "link": "file://person_schema.json"
            }
        ],
        "json-profiles": [
            {
                "name": "reg_form_prof",
                "defenseAttributes": {
                    "maximumArrayLength": "any",
                    "maximumStructureDepth": "any",
                    "maximumTotalLengthOfJSONData": 1000,
                    "maximumValueLength": "any",
                    "tolerateJSONParsingWarnings": false
                },
                "validationFiles": [
                    {
                        "isPrimary": true,
                        "jsonValidationFile": {
                            "fileName": "person_schema.json"
                        }
                    }
                ]
            }
        ],
        "urls": [
            {
                "name": "/register",
                "type": "explicit",
                "method": "POST",
                "attackSignaturesCheck": true,
                "clickjackingProtection": false,
                "disallowFileUploadOfExecutables": false,
                "isAllowed": true,
                "mandatoryBody": false,
                "methodsOverrideOnUrlCheck": false,
                "urlContentProfiles": [
                    {
                        "contentProfile": {
                            "name": "reg_form_prof"
                        },
                        "headerName": "*",
                        "headerOrder": "default",
                        "headerValue": "*",
                        "type": "json"
                    }
                ]
            }
        ]
    }
}

The schema file is identified by the filename property. It is a good practice to keep the filename identical to the one on the URL path, but it is not an error to have different names for each.

if you want to reference the file externally, replace the content of the link property with an HTTP or HTTPS URL:

{
    "json-validation-files": [
        {
            "fileName": "person_schema.json",
            "link": "https://git.mydomain.com/my_app/person_schema.json"
        }
    ]
}

Additional Configuration Options

XFF Headers and Trust

XFF trust is disabled by default but can be enabled.

In this example, we use the default configuration but enable the trust of XFF header.

{
    "policy": {
        "name": "xff_enabled",
        "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "general": {
            "customXffHeaders": [],
            "trustXff": true
        }
    }
}

In this example, we configure a policy with a custom-defined XFF header.

{
    "policy": {
        "name": "xff_custom_headers",
        "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "general": {
            "customXffHeaders": [
                "xff"
            ],
            "trustXff": true
        }
    }
}

Blocking Page Customization

You can customize the blocking page text and formatting to suit your particular design requirements.

In this example, we use the default configuration but modify the response page that is displayed to the customer.

 {
    "policy": {
        "name": "blocking_page",
        "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "response-pages": [
            {
                "responseContent": "<html><head><title>Custom Reject Page</title></head><body>This is a custom response page; it is supposed to overwrite the default page with custom text.<br><br>Your support ID is: <%TS.request.ID()%><br><br><a href='javascript:history.back();'>[Go Back]</a></body></html>",
                "responseHeader": "HTTP/1.1 200 OK\r\nCache-Control: no-cache\r\nPragma: no-cache\r\nConnection: close",
                "responseActionType": "custom",
                "responsePageType": "default"
            }
        ]
    }
}

AJAX Response Page for Single Page Applications (SPAs)

There is a special scenario where default or regular custom response pages cannot be used. SPAs (Single Page Applications) are applications that provide application functionality within the boundaries of a single HTML page. Once a SPA application has been loaded in the browser, it typically makes REST API calls to remote resources expecting JSON response bodies rather than HTML markup. If this SPA application were to receive a default HTML-formatted block page, it would not be able to interpret this, likely causing an application error.

A way to handle such a situation is via configuring an AJAX response page. The AJAX response page will cause a pop-up to appear on the client browser, informing them that the request has been blocked.

In this example, we set up an AJAX response page.

{
    "policy": {
        "name": "NGINX-SPA",
        "description": "Policy with AJAX response page enabled for blocking AJAX requests",
        "template": {
            "name": "POLICY_TEMPLATE_NGINX_BASE"
        },
        "enforcementMode": "blocking",
        "response-pages": [
            {
                "responsePageType": "ajax",
                "ajaxEnabled": true,
                "ajaxPopupMessage": "My customized popup message! Your support ID is: <%TS.request.ID()%>"
            }
        ]
    }
}

Response Page for gRPC Applications

Another scenario where default or regular custom response pages cannot be used is in the context of a gRPC application. If a gRPC client were to receive a block page, it would not be able to interpret this, likely causing an application error.

A way to handle such a situation is via configuring a custom response in a format that a gRPC client can interpret in its error handling code. This is an example configuration for this scenario.

{
    "policy": {
        "name": "NGINX-GRPC",
        "description": "Policy with gRPC response page enabled for blocking gRPC requests",
        "template": {
            "name": "POLICY_TEMPLATE_NGINX_BASE"
        },
        "enforcementMode": "blocking",
        "response-pages": [
            {
                "responseContent": "",
                "responseHeader": "HTTP/1.1 403 FORBIDDEN\r\nContent-Type: application/grpc+proto\r\nGrpc-status: 7\r\nGrpc-message: Blocked by NGINX App Protect, Your support ID is <%TS.request.ID()%>\r\nSupport-ID: <%TS.request.ID()%>\r\nCache-Control: no-cache\r\nPragma: no-cache\r\nConnection: close",
                "responseActionType": "custom",
                "responsePageType": "default"
            }
        ]
    }
}

Modifying Configurations

What we have been seeing so far has been related to making changes by actually overriding specific configuration values. What would happen in the case we wanted to remove a specific configuration entity from the policy. For example, let’s say we have added file types “aaa”, “bbb”, and “ccc”, and now we wish to remove “bbb” from the list of disallowed file types. Deleting this entity from the declarative configuration file will simply mean that this entity will be left intact when the policy is rebuilt, meaning that the entity is still in the disallowed file types list. To resolve such situations, we have a modifications section where we can force modification where otherwise it is not possible using direct declarative configuration.

There is a specific section named modifications where we can configure items to be removed/deleted or forcefully modified in the policy.

In this example, we specify that we wish to remove the file type log from the disallowed file types list.

{
    "policy": {
        "name": "modifying_disallowed_file_types",
        "template": {
            "name": "POLICY_TEMPLATE_NGINX_BASE"
        },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking"
    },
    "modifications": [
        {
            "entityChanges": {
                "type": "explicit"
            },
            "entity": {
                "name": "log"
            },
            "action": "delete",
            "entityType": "filetype"
        }
    ]
}

External References

External references in policy are defined as any code blocks that can be used as part of the policy without being explicitly pasted within the policy file. This means that you can have a set of pre-defined configurations for parts of the policy, and you can incorporate them as part of the policy by simply referencing them. This would save a lot of overhead having to concentrate everything into a single policy file.

A perfect use case for external references is when you wish to build a dynamic policy that depends on moving parts. You can have code create and populate specific files with the configuration relevant to your policy, and then compile the policy to include the latest version of these files, ensuring that your policy is always up-to-date when it comes to a constantly changing environment.

Note: Any update of a single file referenced in the policy will not trigger a policy compilation. This action needs to be done actively by reloading the NGINX configuration.

To use the external references capability, in the policy file the direct property is replaced by “xxxReference” property, where xxx defines the replacement text for the property changed to singular (if originally plural) and notation converted from snake case to camelCase. For example, modifications section is replaced by modificationReference and data-guard is replaced by dataGuardReference.

Types of References

There are different implementations based on the type of references that are being made.

URL Reference

URL reference is the method of referencing an external source by providing its full URL. This is a very useful method when trying to combine or consolidate parts of the policy that are present on different server machines.

Note: You need to make sure that the server where the resource files are located is always available when you are compiling your policy.

Example Configuration

In this example, we are creating a skeleton policy, then enabling the file type violation. However, we do not wish to specify the file types as these file types depend on an app that defines these types. We therefore wish to have this section populated from an external reference. Please note that the filetypes section is replaced by the filetypeReference section. For a list of all the available reference options, please consult with the documentation (declarative section). In the filetypeReference section, we define a key/value pair, where the key defines what type of reference we are making, while the value defines the actual URL to use to reach that reference item.

For the content of the file itself, it is an extension of the original JSON format for the policy, as if this section was cut from the policy and pasted into the file.

Policy configuration:

{
    "name": "external_resources_file_types",
    "template": {
        "name": "POLICY_TEMPLATE_NGINX_BASE"
    },
    "applicationLanguage": "utf-8",
    "enforcementMode": "blocking",
    "blocking-settings": {
        "violations": [
            {
                "name": "VIOL_FILETYPE",
                "alarm": true,
                "block": true
            }
        ]
    },
    "filetypeReference": {
        "link": "http://domain.com:8081/file-types.txt"
    }
}

Content of the referenced file file-types.txt:

[
    {
        "name": "*",
        "type": "wildcard",
        "allowed": true,
        "checkPostDataLength": false,
        "postDataLength": 4096,
        "checkRequestLength": false,
        "requestLength": 8192,
        "checkUrlLength": true,
        "urlLength": 2048,
        "checkQueryStringLength": true,
        "queryStringLength": 2048,
        "responseCheck": false
    },
    {
        "name": "pat",
        "allowed": false
    },
    {
        "name": "mat",
        "allowed": false
    }
]

HTTPS Reference

HTTPS references are a special case of URL references. It uses the HTTPS protocol instead of the HTTP protocol. Please make sure that the webserver you are downloading the resources from does also support HTTPS protocol and has certificates setup properly.

  • Certificates must be valid in date (not expired) during the policy compilation.
  • Certificates must be signed by a trusted CA.
  • For Self-signed certificates, you need to make sure to add your certificates to the trusted CA of the machine where App Protect is installed.
  • Certificates must use the exact domain name that the certificate was issued for. For example, SSL will differentiate between domain.com and www.domain.com, considering each a different domain name.
Example Configuration

In this configuration, we are completely satisfied with the basic default policy, and we wish to use it as is. However, we wish to define a custom response page using an external file located on an HTTPS web server. The external reference file contains our custom response page configuration.

Policy configuration:

{
    "name": "external_references_custom_respsonse",
    "template": {
        "name": "POLICY_TEMPLATE_NGINX_BASE"
    },
    "applicationLanguage": "utf-8",
    "enforcementMode": "blocking",
    "responsePageReference": {
        "link": "https://securedomain.com:8081/response-pages.txt"
    }
}

Content of the referenced file response-pages.txt:

[
    {
        "responseContent": "<html><head><title>Custom Reject Page</title></head><body>This is a custom response page, it is supposed to overwrite the default page with custom text.<br><br>Your support ID is: <%TS.request.ID()%><br><br><a href='javascript:history.back();'>[Go Back]</a></body></html>",
        "responseHeader": "HTTP/1.1 200 OK\r\nCache-Control: no-cache\r\nPragma: no-cache\r\nConnection: close",
        "responseActionType": "custom",
        "responsePageType": "default"
    }
]
Example Configuration

In this example, we would like to enable all attack signatures. Yet, we want to exclude specific signatures from being enforced.

Policy configuration:

{
    "policy": {
        "name": "external_resources_signature_modification",
        "template": {
            "name": "POLICY_TEMPLATE_NGINX_BASE"
        },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "signature-sets": [
            {
                "name": "All Signatures",
                "block": true,
                "alarm": true
            }
        ]
    },
    "modificationsReference": {
        "link": "http://my-domain.com:8081/modifications.txt"
    }
}

Content of the referenced file modifications.txt:

{
    "modifications": [
        {
            "entityChanges": {
                "enabled": false
            },
            "entity": {
                "signatureId": 200001834
            },
            "entityType": "signature",
            "action": "add-or-update"
        }
    ]
}

File Reference

File references refers to accessing local resources on the same machine, as opposed to accessing a remote resource on another server/machine. The user can specify any location that is accessible by App Protect except for the root folder (“/”). If no full path is provided, the default path /etc/app_protect/conf will be assumed. Note that file references can only be on the local machine: you cannot use remote hosts!

Here are some examples of the typical cases:

Link URL Format (examples) File Path Comment
file:///foo.json /etc/app_protect/conf/foo.json Default directory assumed
file://foo.json /etc/app_protect/conf/foo.json Formally illegal, but tolerated as long as there is no trailing slash.
file:///etc/app_protect/conf/foo.json /etc/app_protect/conf/foo.json Full path, but still the default one
file:///bar/foo.json /bar/foo.json Non-default path
file://etc/app_protect/conf/foo.json Not accepted “etc” is interpreted as remote host name
Example Configuration

In this example, we would like to enable all attack signatures. Yet, we want to exclude specific signatures from being enforced. To do this, we reference a local file on the machine.

Policy Configuration:

{
    "policy": {
        "name": "external_resources_signature_modification",
        "template": {
            "name": "POLICY_TEMPLATE_NGINX_BASE"
        },
        "applicationLanguage": "utf-8",
        "enforcementMode": "blocking",
        "signature-sets": [
            {
                "name": "All Signatures",
                "block": true,
                "alarm": true
            }
        ]
    },
    "modificationsReference": {
        "link": "file:///modifications.txt"
    }
}

Content of the referenced file modifications.txt:

{
    "modifications": [
        {
            "entityChanges": {
                "enabled": false
            },
            "entity": {
                "signatureId": 200001834
            },
            "entityType": "signature",
            "action": "add-or-update"
        }
    ]
}

Configuration Errors

If, for any reason, the configuration was done incorrectly, the policy compilation process will fail with the following error:

APP_PROTECT { "event": "configuration_load_failure" ...

The error details that follow will depend on the exact situation causing the policy compilation to fail. If the policy compilation process fails, the compiler will revert to the last working policy and all the changes for the last policy compilation attempt will be lost.

OpenAPI Specification File Reference

The OpenAPI Specification defines the spec file format needed to describe RESTful APIs. The spec file can be written either in JSON or YAML. Using a spec file simplifies the work of implementing API protection. Refer to the OpenAPI Specification (formerly called Swagger) for details.

The simplest way to create an API protection policy is using an OpenAPI Specification file to import the details of the APIs. If you use an OpenAPI Specification file, NGINX App Protect will automatically create a policy for the following properties (depending on what’s included in the spec file):

  • Methods
  • URLs
  • Parameters
  • JSON profiles

An OpenAPI-ready policy template is provided with the NGINX App Protect packages and is located in: /etc/nginx/NginxApiSecurityPolicy.json

It contains violations related to OpenAPI set to blocking (enforced).

Note: NGINX App Protect supports only one OpenAPI Specification file reference per policy.

Types of OpenAPI References

There are different ways of referencing OpenAPI Specification files. The configuration is similar to External References.

Note: Any update of an OpenAPI Specification file referenced in the policy will not trigger a policy compilation. This action needs to be done actively by reloading the NGINX configuration.

URL Reference

URL reference is the method of referencing an external source by providing its full URL.

Make sure to configure certificates prior to using the HTTPS protocol - see the External References for details.

Note: You need to make sure that the server where the resource files are located is always available when you are compiling your policy.

Example Configuration

In this example, we are adding an OpenAPI Specification file reference to /etc/nginx/NginxApiSecurityPolicy.json using the link http://127.0.0.1:8088/myapi.yaml. This will configure allowed data types for query_int and query_str parameters values.

Policy configuration:

{
    "policy": {
        "name": "petstore_api_security_policy",
        "description": "NGINX App Protect API Security Policy for the Petstore API",
        "template": {
            "name": "POLICY_TEMPLATE_NGINX_BASE"
        },
        "open-api-files": [
            {
                "link": "http://127.0.0.1:8088/myapi.yaml"
            }
        ],
        "blocking-settings": {
            "violations": [
                {
                    "block": true,
                    "description": "Disallowed file upload content detected in body",
                    "name": "VIOL_FILE_UPLOAD_IN_BODY"
                },
                {
                    "block": true,
                    "description": "Mandatory request body is missing",
                    "name": "VIOL_MANDATORY_REQUEST_BODY"
                },
                {
                    "block": true,
                    "description": "Illegal parameter location",
                    "name": "VIOL_PARAMETER_LOCATION"
                },
                {
                    "block": true,
                    "description": "Mandatory parameter is missing",
                    "name": "VIOL_MANDATORY_PARAMETER"
                },
                {
                    "block": true,
                    "description": "JSON data does not comply with JSON schema",
                    "name": "VIOL_JSON_SCHEMA"
                },
                {
                    "block": true,
                    "description": "Illegal parameter array value",
                    "name": "VIOL_PARAMETER_ARRAY_VALUE"
                },
                {
                    "block": true,
                    "description": "Illegal Base64 value",
                    "name": "VIOL_PARAMETER_VALUE_BASE64"
                },
                {
                    "block": true,
                    "description": "Disallowed file upload content detected",
                    "name": "VIOL_FILE_UPLOAD"
                },
                {
                    "block": true,
                    "description": "Illegal request content type",
                    "name": "VIOL_URL_CONTENT_TYPE"
                },
                {
                    "block": true,
                    "description": "Illegal static parameter value",
                    "name": "VIOL_PARAMETER_STATIC_VALUE"
                },
                {
                    "block": true,
                    "description": "Illegal parameter value length",
                    "name": "VIOL_PARAMETER_VALUE_LENGTH"
                },
                {
                    "block": true,
                    "description": "Illegal parameter data type",
                    "name": "VIOL_PARAMETER_DATA_TYPE"
                },
                {
                    "block": true,
                    "description": "Illegal parameter numeric value",
                    "name": "VIOL_PARAMETER_NUMERIC_VALUE"
                },
                {
                    "block": true,
                    "description": "Parameter value does not comply with regular expression",
                    "name": "VIOL_PARAMETER_VALUE_REGEXP"
                },
                {
                    "block": true,
                    "description": "Illegal URL",
                    "name": "VIOL_URL"
                },
                {
                    "block": true,
                    "description": "Illegal parameter",
                    "name": "VIOL_PARAMETER"
                },
                {
                    "block": true,
                    "description": "Illegal empty parameter value",
                    "name": "VIOL_PARAMETER_EMPTY_VALUE"
                },
                {
                    "block": true,
                    "description": "Illegal repeated parameter name",
                    "name": "VIOL_PARAMETER_REPEATED"
                }
            ]
        }
    }
}

Content of the referenced file myapi.yaml:

openapi: 3.0.1
info:
  title: 'Primitive data types'
  description: 'Primitive data types.'
  version: '2.5.0'
servers:
  - url: http://localhost
paths:
  /query:
    get:
      tags:
        - query_int_str
      description: query_int_str
      operationId: query_int_str
      parameters:
        - name: query_int
          in: query
          required: false
          allowEmptyValue: false
          schema:
            type: integer
        - name: query_str
          in: query
          required: false
          allowEmptyValue: true
          schema:
            type: string           
      responses:
        200:
          description: OK
        404:
          description: NotFound

In this case the following request will trigger an Illegal parameter data type violation, as we expect to have an integer value in the query_int parameter:

http://localhost/query?query_int=abc

The request will be blocked.

The link option is also available in the openApiFileReference property and synonymous to the one above in open-api-files

Note: openApiFileReference is not an array.

Example Configuration

In this example, we reference the same OpenAPI Specification file as in the policy above using the openApiFileReference property.

Policy configuration:

{
    "name": "openapifilereference-yaml",
    "template": {
        "name": "POLICY_TEMPLATE_NGINX_BASE"
    },
    "openApiFileReference": {
        "link": "http://127.0.0.1:8088/ref.txt"
    }
}

Content of the file ref.txt:

[
    {
        "link": "http://127.0.0.1:8088/myapi.yaml"
    }
]

File Reference

File reference refers to accessing local resources on the same machine. See the External References for details.

Example Configuration

In this example, we would like to add an OpenAPI Specification file reference to the default policy.

Policy Configuration:

{
    "name": "openapi-file-reference-json",
    "template": {
        "name": "POLICY_TEMPLATE_NGINX_BASE"
    },
    "open-api-files": [
        {
            "filename": "file://myapi2.json"
        }
    ]
}

Content of the referenced file myapi2.json:

{
    "openapi": "3.0.1",
    "info": {
        "title": "Primitive data types2",
        "description": "Primitive data types.",
        "version": "2.5.1"
    },
    "servers": [
        {
            "url": "http://localhost"
        }
    ],
    "paths": {
        "/query": {
            "get": {
                "tags": [
                    "query_bool"
                ],
                "description": "query_bool",
                "operationId": "query_bool",
                "parameters": [
                    {
                        "name": "query_bool",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "boolean"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "404": {
                        "description": "NotFound"
                    }
                }
            }
        }
    }
}

In this case the following request will trigger an Illegal repeated parameter name violation, as the OpenAPI Specification doesn’t allow repeated parameters.

http://localhost/query?a=true&a=false

The request will not be blocked because this violation is set to alarm in the default policy.

Directives

Global Directives

Global configuration consists of a series of nginx.conf directives at the http context controlling aspects that are not specific to a specific application.

When applied to a cluster, all cluster members will get the same globals as expected.

Note: Whether an incoming request is inspected by NGINX App Protect may be determined by the URL in the request. This happens if you configure app_protect_enable and app_protect_policy_file directives in the location scope. In the case where the URL itself has violations such as bad unescape or illegal metacharacter then the request might be assigned to a location in which NGINX App Protect is disabled or has a relaxed policy that does not detect these violations. Such malicious requests will be allowed without inspection. In order to avoid this, it is recommended to have a basic policy enabled at the http scope or at least at the server scope to process malicious requests in a more complete manner.

Directive Name Syntax Description Default
app_protect_physical_memory_util_thresholds app_protect_physical_memory_util_thresholds high=<number_0-100> low=<number_0-100> Sets the physical memory utilization thresholds for entering (high) and exiting (low) failure mode. When the high threshold is exceeded the system enters failure mode until memory drops below the low threshold. Setting the value of 100 disables this feature. high=low=100 (disabled)
app_protect_cpu_thresholds app_protect_cpu_thresholds high=<number_0-100> low=<number_0-100>
Sets the CPU utilization thresholds for entering and exiting failure mode respectively: when the high threshold is exceeded the system enters failure mode until CPU drops below the low threshold. Setting the value of 100 disables this feature.
Note: The system does not enter failure mode during policy compilation after reload even if the threshold is exceeded.
high=low=100 (disabled)
app_protect_failure_mode_action app_protect_failure_mode_action pass | drop
How to handle requests when the App Protect Enforcer cannot process them, either because it is down, disconnected or because of excessive CPU or memory utilization. There are two values:
  • pass: Pass the request without App Protect Enforcer inspection, a.k.a. “fail-open”.
  • drop: Drop the request by returning the response “503 Service Unavailable”, a.k.a. “fail-close”.
pass
app_protect_cookie_seed app_protect_cookie_seed <string> A long randomized string that serves to generate the encryption key for the cookies generated by App Protect. The string should contain only alphanumeric characters and be no longer than 1000 characters. Auto-generated random string
app_protect_compressed_requests_action app_protect_compressed_requests_action pass | drop
Determines how to handle compressed requests. There are two values:
  • pass: Pass the request without App Protect Enforcer inspection, a.k.a. “fail-open”.
  • drop: Drop the request by returning the response “501 Not Implemented”, a.k.a. “fail-close”.
drop
app_protect_request_buffer_overflow_action app_protect_request_buffer_overflow_action pass | drop
Determines how to handle requests in case the NGINX request buffer is full and requests cannot be buffered anymore. There are two values:
  • pass: Pass the request without App Protect Enforcer inspection, a.k.a. “fail-open”.
  • drop: Drop the request by resetting connection. No response page is returned, a.k.a. “fail-close”.
pass
app_protect_user_defined_signatures app_protect_user_defined_signatures <path> Imports the user-defined tagged signature file with the respective tag name from the provided path. Multiple instances of this directive are supported. In order to import multiple signatures files, each file must have a different tag. N/A

App Protect Specific Directives

This table summarizes the nginx.conf directives for NGINX App Protect functionality.

Directive Name Syntax Functionality nginx.conf Contexts Example
load_module load_module <library_file_path> NGNIX directive to load the App Protect module. It must be invoked with the App Protect library path Global load_module /lib/app_protect.so
app_protect_enable app_protect_enable on | off Whether to enable App Protect at the respective context. If not present, inherits from the parent context HTTP, Server, Location app_protect_enable on
app_protect_policy_file app_protect_policy_file <file_path> Set a App Protect policy configuring behavior for the respective context. HTTP, Server, Location app_protect_policy /config/waf/strict_policy.json
app_protect_security_log_enable app_protect_security_log_enable on | off Whether to enable the App Protect per-request log at the respective context. HTTP, Server, Location app_protect_security_log_enable on
app_protect_security_log app_protect_security_log <file_path> <destination> Specifies the per-request logging: what to log and where HTTP, Server, Location app_protect_security_log /config/waf/log_illegal.json syslog:localhost:522

Horizontal Scaling

NGINX App Protect can be deployed in multiple instances that share the traffic to the same applications. In that case all the instances must share the same configuration files. It is your responsibility to synchronize the files on all instances. You also have to provide a load balancing solution in front of those instances such as another NGINX instance.

When deploying multiple scalability instances you have to add the app_protect_cookie_seed directive to nginx.conf in the http block:

...
http {
    ...
    app_protect_cookie_seed jkldsf90upiokasdj120;
    ...
    server {
        listen       80;
...
}
...

As the argument of this directive, put a random alphanumeric string of at least 20 characters length (but not more than 1000 characters). That seed is used by NGINX App Protect to generate the encryption key for the cookies it creates. These cookies are used for various purposes such as validating the integrity of the cookies generated by the application.

In the absence of this directive, App Protect generates a random string by itself. In that case, each instance will have a different seed. A cookie created and encrypted on one instance of App Protect will fail to be decrypted when sent by the same client to another App Protect instance having a different encryption key.

Failure Mode

If the App Protect daemons are down or disconnected from the NGINX workers, there are two modes of operation until they are up and connected again:

  • Pass the traffic without inspection. Use this when preferring availability over security. This mode is also known as “fail open”.
  • Drop the traffic. Use this when preferring security over availability. This mode is also known as “fail closed”.

The default is to pass, fail open, but you can control this using the app_protect_failure_mode_action directive with one argument with two possible values: “pass” or “fail” for the two above options.

This directive is also placed in the http block of the nginx.conf file.

...
http {
    ...
    app_protect_failure_mode_action drop;
    ...
    server {
        listen       80;
...
    }
...

Handling Compressed Requests

Requests with compressed body encoding are rarely used and NGINX App Protect does not support them. Similar to failure mode, you can decide what to do with those requests. Either:

  • Pass the traffic without inspection, or
  • Drop the traffic. This is the preferred option as passing would create a security breach.

The default is to Drop, fail open, but you can control this using the app_protect_compressed_requests_action directive with one argument with two possible values: “pass” or “fail” for the two above options.

This directive is also placed in the http block of the nginx.conf file.

...
http {
    ...
    app_protect_compressed_requests_action drop;
    ...
    server {
        listen       80;
...
    }
...

Violations

App Protect violations are rated by the App Protect algorithms to help distinguish between attacks and potential false positive alerts. A violation rating is a numerical rating that our algorithms give to requests based on the presence of violation(s). Each violation type and severity contributes to the calculation of the final rating. The final rating then defines the action taken for the specific request. As per the default policy, any violation rating of 1, 2 and 3 will not cause the request to be blocked and only a log will be generated with alerted status. If the violation rating is 4 or 5, the request is blocked: a blocking page is displayed and a log generated for the transaction with blocked status. Violation ratings are displayed in the logs by default.

Supported Violations

The following violations are supported and can be enabled by turning on the alarm and/or block flags.

Violation Name Title Enabled Flags in Default Template Description Comment
VIOL_ASM_COOKIE_MODIFIED Modified ASM cookie Alarm The system checks that the request contains an ASM cookie that has not been modified or tampered with. Blocks modified requests.  
VIOL_ATTACK_SIGNATURE Attack signature detected N/A The system examines the HTTP message for known attacks by matching it against known attack patterns. Determined per signature set.
VIOL_BLACKLISTED_IP IP is in the deny list Alarm The violation is issued when a request comes from an IP address that falls in the range of an IP address exception marked for “always blocking”, that is, the deny list of IPs. Would trigger Violation Rating of 5.
VIOL_COOKIE_EXPIRED Expired timestamp Alarm The system checks that the timestamp in the HTTP cookie is not old. An old timestamp indicates that a client session has expired. Blocks expired requests. The timestamp is extracted and validated against the current time. If the timestamp is expired and it is not an entry point, the system issues the Expired Timestamp violation.  
VIOL_COOKIE_LENGTH Illegal cookie length Alarm The system checks that the request does not include a cookie header that exceeds the acceptable length specified in the security policy. Determined by policy setting which is disabled in default template.
VIOL_COOKIE_MALFORMED Cookie not RFC-compliant Alarm

This violation occurs when HTTP cookies contain at least one of the following components:

  • Quotation marks in the cookie name.
  • A space in the cookie name.
  • An equal sign (=) in the cookie name. Note: A space between the cookie name and the equal sign (=), and between the equal sign (=) and cookie value is allowed.
  • An equal sign (=) before the cookie name.
  • A carriage return (hexadecimal value of 0xd) in the cookie name.
 
VIOL_COOKIE_MODIFIED Modified domain cookie(s) Alarm The system checks that the web application cookies within the request have not been tampered, and the system checks that the request includes a web application cookie defined in the security policy. Determined by cookie type: applied to “enforced” cookies.
VIOL_DATA_GUARD Data Guard: Information leakage detected Alarm The system examines responses and searches for sensitive information. Controlled by the DG enable flag which is disabled in default template.
VIOL_ENCODING Failed to convert character Alarm The system detects that one of the characters does not comply with the configured language encoding of the web application’s security policy. Enforced by NGINX core, reported by App Protect.
VIOL_EVASION Evasion technique detected Alarm This category contains a list of evasion techniques that attackers use to bypass detection.  
VIOL_FILETYPE Illegal file type Alarm The system checks that the requested file type is configured as a valid file type, or not configured as an invalid file type, within the security policy. Only for disallowed file types.
VIOL_HEADER_LENGTH Illegal header length Alarm The system checks that the request includes a total HTTP header length that does not exceed the length specified in the security policy. The actual size in default policy is 4 KB
VIOL_HEADER_METACHAR Illegal meta character in header Alarm The system checks that the values of all headers within the request only contain meta characters defined as allowed in the security policy.  
VIOL_HTTP_PROTOCOL HTTP protocol compliance failed Alarm This category contains a list of validation checks that the system performs on HTTP requests to ensure that the requests are formatted properly.  
VIOL_HTTP_RESPONSE_STATUS Illegal HTTP response status Alarm The server response contains an HTTP status code that is not defined as valid in the security policy.  
VIOL_JSON_FORMAT JSON data does not comply with format settings Alarm The system checks that the request contains JSON content and complies with the various request limits within the defense configuration in the security policy’s JSON profile. Enforces valid JSON requests and protects the server from JSON parser attacks. This violation is generated when a problem is detected in a JSON request, generally checking the message according to boundaries such as the message’s size and meta characters in parameter value. Controlled from the default JSON profile.
VIOL_JSON_MALFORMED Malformed JSON data Alarm The system checks that the request contains JSON content that is well-formed. Enforces parsable JSON requests.  
VIOL_METHOD Illegal method Alarm The system checks that the request references an HTTP request method that is found in the security policy. Enforces desired HTTP methods; GET and POST are always allowed.

These HTTP methods are supported:

  • GET
  • HEAD
  • POST
  • PUT
  • PATCH
  • DELETE
  • OPTIONS
VIOL_POST_DATA_LENGTH Illegal POST data length Alarm The system checks that the request contains POST data whose length does not exceed the acceptable length specified in the security policy. In * file type entity. This check is disabled by default.
VIOL_QUERY_STRING_LENGTH Illegal query string length Alarm The system checks that the request contains a query string whose length does not exceed the acceptable length specified in the security policy. In * file type entity. Actual size is 2 KB.
VIOL_REQUEST_LENGTH Illegal request length Alarm The system checks that the request length does not exceed the acceptable length specified in the security policy per the requested file type. In * file type entity. This check is disabled by default.
VIOL_REQUEST_MAX_LENGTH Request length exceeds defined buffer size Alarm The system checks that the request length is not larger than the maximum memory buffer size of the ASM. Note that this is a BIG-IP unit parameter that protects the ASM from consuming too much memory across all security policies which are active on the device. Default is 10MB
VIOL_URL_LENGTH Illegal URL length Alarm The system checks that the request is for a URL whose length does not exceed the acceptable length specified in the security policy. In * file type entity. Actual size is 2 KB.
VIOL_URL_METACHAR Illegal meta character in URL Alarm The system checks that the incoming request includes a URL that contains only meta characters defined as allowed in the security policy. Enforces a desired set of acceptable characters.  
VIOL_XML_FORMAT XML data does not comply with format settings Alarm The system checks that the request contains XML data that complies with the various document limits within the defense configuration in the security policy’s XML profile. Enforces proper XML requests and the data failed format/defense settings such as the maximum document length. This violation is generated when a problem in an XML document is detected (for example, an XML bomb), generally checking the message according to boundaries such as the message’s size, maximum depth, and maximum number of children. Controlled by the default XML profile
VIOL_XML_MALFORMED Malformed XML data Alarm The system checks that the request contains XML data that is well-formed, according to W3C standards. Enforces proper XML requests.  
VIOL_RATING_THREAT Request is likely a threat Alarm and Block The combination of violations in this request determined that the request is likely to be a threat. For VR = 4 or 5
VIOL_RATING_NEED_EXAMINATION Request needs further examination Disabled The combination of violations could not determine whether the request is a threat or violations are false positives thus requiring more examination. For VR = 3
VIOL_PARAMETER_MULTIPART_NULL_VALUE Null in multi-part parameter value Disabled

The system checks that the multi-part request has a parameter value that does not contain the NULL character (0x00). If a multipart parameter with binary content type contains NULL in its value, the enforcer issues this violation. The exceptions to this are:

  • If that parameter is configured in the policy as “Ignore value”.
  • If that parameter is configured in the security policy as “user-input file upload”.
  • If the parameter has a content-type that contains the string ‘XML’ and the parameter value contains a valid UTF16 encoded XML document (the encoding is valid). In this case NULL is allowed as it is part of the UTF16 encoding.
 
VIOL_PARAMETER_NAME_METACHAR Illegal meta character in parameter name Alarm The system checks that all parameter names within the incoming request only contain meta characters defined as allowed in the security policy.  
VIOL_PARAMETER_VALUE_METACHAR Illegal meta character in value Alarm The system checks that all parameter values, XML element/attribute values, or JSON values within the request only contain meta characters defined as allowed in the security policy. Enforces proper input values.  
VIOL_THREAT_CAMPAIGN Threat campaign detected Block The system examines the HTTP message for known threat campaigns by matching it against known attack patterns.  

HTTP Compliance Sub-Violations

The following table specifies the HTTP Compliance sub-violation settings. All are supported in NGINX, but not all are enabled in the default App Protect security template. The table specifies which. Some of the checks are enforced by NGINX Plus and App Protect only gets a notification. Note: In this case, the request is always blocked regardless of the App Protect policy.

Sub-Violation Default Template Enforced by Description
Unparsable request content Enabled NGINX This violation is triggered when the system’s parser cannot parse the message.
Several Content-Length headers Enabled NGINX More than one content-length header is a non RFC violation. Indicates an HTTP response splitting attack.
POST request with Content-Length: 0 Disabled App Protect POST request is usually sent with request body. This sub-violation is issued when a request has empty or no body at all.
Null in request Enabled Null in header - NGINX, null in body - App Protect The system issues a violation for requests with a NULL character anywhere in the request (except for a NULL in the binary part of a multipart request).
No Host header in HTTP/1.1 request Enabled NGINX Examines requests using HTTP/1.1 to see whether they contain a “Host” header.
Multiple host headers Enabled App Protect Examines requests to ensure that they contain only a single “Host” header.
Host header contains IP address Enabled App Protect The system verifies that the request’s host header value is not an IP address to prevent non-standard requests.
High ASCII characters in headers Enabled NGINX Checks for high ASCII characters in headers (greater than 127).
Header name with no header value Disabled App Protect The system checks for a header name without a header value.
CRLF characters before request start Enabled App Protect Examines whether there is a CRLF character before the request method. If there is, the system issues a violation.
Content length should be a positive number Enabled NGINX The Content-Length header value should be greater than zero; only a numeric positive number value is accepted.
Chunked request with Content-Length header Enabled App Protect The system checks for a Content-Length header within chunked requests.
Check maximum number of parameters Enabled: 500 App Protect The system compares the number of parameters in the request to the maximum configured number of parameters.
Check maximum number of headers Enabled : 50 App Protect The system compares the request headers to the maximal configured number of headers.
Unescaped space in URL Enabled App Protect The system checks that there is no unescaped space within the URL in the request line. Such spaces split URLs introducing ambiguity on picking the actual one.
Body in GET or HEAD requests Disabled App Protect Examines GET and HEAD requests which have a body.
Bad multipart/form-data request parsing Enabled App Protect When the content type of a request header contains the substring “Multipart/form-data”, the system checks whether each multipart request chunk contains the strings “Content-Disposition” and “Name”. If they do not, the system issues a violation.
Bad multipart parameters parsing Enabled App Protect
The system checks the following:
  1. A boundary follows immediately after request headers.
  2. The parameter value matches the format: ‘name=”param_key”;rn.
  3. A chunked body contains at least one CRLF.
  4. A chunked body ends with CRLF.
  5. Final boundary was found on multipart request.
  6. There is no payload after final boundary.

If one of these is false, the system issues a violation.

Bad HTTP version Enabled NGINX Enforces legal HTTP version number (only 0.9 or higher allowed).
Bad host header value Enabled NGINX Detected non RFC compliant header value.

Evasion Techniques Sub-Violations

The following table specifies the Evasion Techniques sub-violation settings. All are supported in NGINX Plus.

Sub-Violation Default Template Description
%u decoding Enabled Performs Microsoft %u unicode decoding (%UXXXX where X is a hexadecimal digit). For example, the system turns a%u002fb to a/b. The system performs this action on URI and parameter input to evaluate if the request contains an attack.
Apache whitespace Enabled The system detects the following characters in the URI: 9 (0x09), 11 (0x0B), 12 (0x0C), and 13 (0x0D).
Bad unescape Enabled The system detects illegal HEX encoding. Reports unescaping errors (such as %RR).
Bare byte decoding Enabled The system detects higher ASCII bytes (greater than 127).
Directory traversals Enabled Ensures that directory traversal commands like ../ are not part of the URL. While requests generated by a browser should not contain directory traversal instructions, sometimes requests generated by JavaScript have them.
IIS backslashes Enabled Normalizes backslashes () to slashes (/) for further processing.
IIS Unicode codepoints Enabled Handles the mapping of IIS specific non-ASCII codepoints. Indicates that, when a character is greater than ‘0x00FF’, the system decodes %u according to an ANSI Latin 1 (Windows 1252) code page mapping. For example, the system turns a%u2044b to a/b. The system performs this action on URI and parameter input.
Multiple decoding Enabled: 3 The system decodes URI and parameter values multiple times according to the number specified before the request is considered an evasion.

Attack Types

Each signature, factory or user-defined, and violation has an Attack Type, the attack vector it protects from. When you create a user-defined signature you associate it with the most appropriate attack type from the list below. If you do not find an Attack Type that matches the threat for which your signture was written, use Other Application Activity Attack Type. Attach Types are also useful as part of the filter in user-defined signature sets.

Following is the full list of Attack Types supported in App Protect. Use the name of the Attack Type to reference it within the singnature or signature set filter.

Attack Type Name Description
Server-Side Template Injection Some applications use server-side templates for better modularity. This attack occurs when a non-sanitized input containing template directives is embedded into a server-side template which then leads to execution of the injected code when rendered.
Insecure File Upload Many applications allow uploading files to the server, such as images or documents. An application that does not correctly restrict the type of the uploaded files or the upload folder path can be exploited by attackers to upload files, called ‘WebShells’, containing malicious code that later will be executed or override the server configuration.
NoSQL Injection NoSQL databases are non-relational databases, and even though they do not use the SQL syntax, non-sanitized input might let attackers control the original query via a database specific programming language.
Insecure Deserialization This is an attack against an application that receives serialized objects. An application which does not restrict which objects might be deserialized could be exploited by attackers sending specific object called ‘gadgets’, that could trigger arbitrary code execution when deserialized.
XML External Entities (XXE) This is a type of attack against an application that parses XML input. This attack occurs when XML input containing a reference to an external entity is processed by a weakly configured XML parser
Server-Side Request Forgery (SSRF) Some applications receive a URL as input and use it to exchange data with another service. An attacker could provide special URLs to read or update internal resources such as localhost services, cloud metadata servers, internal network web applications or HTTP enabled databases.
Cache Poisoning Cache poisoning is an attack against the integrity of an intermediate Web cache repository, in which genuine content cached for an arbitrary URL is replaced with spoofed content.
WebSocket Parser Attack WebSocket parser attack targets the functionality of the WebSocket parser in order to crash it or force the parser to work abnormally.
GWT Parser Attack This attack targets the functionality of the GWT parser in order to crash it or force the parser to work abnormally.
Cross-site Request Forgery An attacker exploits the web application’s assumption and trust that the authenticated user is purposely sending requests to perform actions or commands, while in fact the attacker is causing the user to send the commands without the user’s knowledge or consent.
JSON Parser Attack This attack targets the functionality of the JSON parser in order to crash it or force the parser to work abnormally.
Malicious File Upload Malicious file upload occurs when a user tries to upload a malicious file to the web application. This could allow remote attackers to cause Server Infection, Network Infection, Buffer Overflow and Remote Comma Execution.
HTTP Response Splitting Specially crafted HTTP messages can manipulate the web server or cache’s standard behavior. This can lead to XSS, and cache poisoning.
Session Hijacking An attacker can steal a valid web session from legitimate users in order to gain unauthorized access.
XML Parser Attack This attack targets the functionality of the XML parser in order to crash it or force the parser to work abnormally.
Parameter Tampering By changing certain parameters in a URL or web page form, attackers can successfully attack the web application business logic.
Injection Attempt This is an attack where an attacker injects OS commands, active script commands (in JavaScript or any other scripting language) or SQL commands into various parts of an HTTP request, in order for the injected content to run on remote systems. The two most common injection attacks are SQL injection and Cross Site Scripting.
Brute Force Attack Brute-force attacks are mainly used for guessing passwords and bypassing access control of an application by executing many different attempts.
Forceful Browsing This attack occurs when an attacker is directly accessing a URL, which could grant access to a restricted part of the web site.
HTTP Request Smuggling Attack Specially crafted HTTP messages can manipulate the web server or cache’s standard behavior. This can lead to XSS, and cache poisoning.
HTTP Parser Attack HTTP parser attack targets the functionality of the HTTP parser in order to crash it or force the parser to work abnormally.
Other Application Activity This attack does not belong to any specific attack category, however it is a violation of the user-defined security policy.
Denial of Service A denial-of-service (DoS) attack represents a family of attacks aimed to exhaust the application server resources up to a point that the application cannot respond to legitimate traffic, either because it has crashed, or because its slow response renders it effectively unavailable.
Cross Site Scripting (XSS) Cross Site Scripting (XSS) occurs when a web application does not sanitize user-supplied input, and places it directly into the page returned to the user. Usually the attacker will submit malicious JavaScript, VBScript, ActiveX, HTML, or Flash code to the vulnerable web site.
SQL-Injection SQL-Injection occurs when a web application does not sanitize user-supplied input, and places it directly into the SQL statement. This attack allows remote attackers to run SQL statements on the internal database
Command Execution Web applications can be tricked to execute operating system commands, injected from a remote machine, if user supplied input is not properly checked by the web application.
Server Side Code Injection An attacker can submit server side code by invalidated input. The web server, when parsing malicious input, may execute operating system commands or access restricted files.
LDAP Injection If user-supplied input is not correctly sanitized, the attacker could change the construction of LDAP statements. Successful exploitation results in information gathering, system integrity compromise, and possible modification of the LDAP tree.
XPath Injection XPath-Injection occurs when a web application does not sanitize user-supplied input but places it directly into the XML document query. Successful exploitation results in information gathering and system integrity compromise.
Path Traversal Path traversal can be used to bypass the web server root and request various files, including system files or private directories and resources. This attack can lead to information disclosure, and possible exposure of sensitive system information.
Directory Indexing This is a directory listing attempt which can lead to information disclosure and possible exposure of sensitive system information. Directory Indexing attacks usually target web servers that are not correctly configured, or which have a vulnerable component that allows Directory Indexing.
Information Leakage Sensitive information may be present within HTML comments, error messages, source code, or simply left in files which are accessible by remote clients. In addition, attackers can manipulate the application to reveal classified information like credit card numbers. This can lead to the disclosure of sensitive system information which may be used by an attacker to further compromise the system.
Predictable Resource Location By making educated guesses, the attacker could discover hidden web site content and functionality, such as configuration, temporary, backup, or sample files. This can lead to the disclosure of sensitive system information which may be used by an attacker to compromise the system.
Buffer Overflow Buffer Overflow could be triggered when data written to memory exceeds the allocated size of the buffer for that data. This could lead to the Denial of Service or arbitrary code execution.
Authentication/Authorization Attacks Authentication/Authorization Attacks occur when a web site permits an attacker to access sensitive content or functionality without having to properly authenticate, or authorize, that resource.
Abuse of Functionality Abuse of Functionality is an attack technique that uses a web site’s own features and functionality to consume, defraud, or circumvent access controls mechanisms.
Vulnerability Scan An attempt is made using an automatic tool to scan a web server, or an application running on a web server, for a possible vulnerability.
Detection Evasion An attempt is made to evade detection of the attack on a web server, by obfuscating the attack using various methods such as encodings and path manipulation.
Trojan/Backdoor/Spyware This is an attack initiated by some form of malicious code.
Other Application Attacks This is an attack which targets the web application and does not fall in any predefined category
Non-browser Client An attempt is made by a non-browser client to explore the site.
Remote File Include Remote File Inclusion attacks allow attackers to run arbitrary code on a vulnerable website.

Security Logs

Overview

Security logs (also known as Request logs or Traffic logs) contain information on HTTP requests and responses, how App Protect processes them, and the final decision made based on the configured policy parameters. The policy configuration defines the information contained in the Security log, such as whether requests are passed, blocked or alerted, due to violations, attack signatures, and other criteria.

App Protect uses its own logging mechanism for request logging rather than NGINX’s access logging mechanism (which is NGINX’s default logging mechanism).

The Security log has the following properties:

  • Log Configuration: app_protect_security_log directive referencing security_log.json file

  • Configuration contexts: nginx.conf: http, server, location

  • File Destination? Yes. You can set the destination to either stderr, or an absolute path to a local file, or you can use syslog, and redirect the log with Netcat and pipe:

    nc -vv -l “[ip]” “[port]” > “[name_of_file]” 2>&1
    
  • Syslog Destination? Yes

Directives in nginx.conf

app_protect_security_log_enable

This directive determines whether security logging will be enabled in the respective context.

The security log attributes are determined by the app_protect_security_log directive. The directive can be at the following contexts: http, server and location. When not present at a certain context, the directive is inherited from the context above it: location from server, then from http. If there is no directive at any of these context levels, then the logging is disabled for the respective context.

• Syntax: app_protect_security_log_enable on | off

• Levels: http, server, location

• Example: app_protect_security_log_enable on

Arguments
Argument Mandatory Meaning Default
ON-OFF Yes Whether to enable logging or not off

app_protect_security_log

The security log attributes are determined by the app_protect_security_log directive, if it was enabled in the respective context. The directive can be at the following context levels: http, server and location. When not present at a certain context, the directive is inherited from the context above it: location from server, then from http. If there is no directive at any of these context levels, but logging is enabled then the default is used for the respective context.

• Syntax: app_protect_security_log [LOG-CONFIG-FILE] [DESTINATION]

• Levels: http, server, location

• Examples:

app_protect_security_log "/etc/app_protect/conf/log_default.json" syslog:server=localhost:5144;
app_protect_security_log "/etc/app_protect/conf/log_default.json" /var/log/app_protect/security.log;
app_protect_security_log "/etc/app_protect/conf/log_default.json" stderr;

Note: When using stderr, please make sure that the process bd-socket-plugin is not redirecting the stderr output to file.
- When using the Docker entrypoint.sh startup script from the admin guide, make sure that it doesn’t redirect stderr.
- When using services startup, make sure that the service startup file for nginx-app-protect.service doesn’t redirect stderr.

Arguments
Argument Mandatory Meaning Default
LOG-CONFIG-FILE No The path to the log configuration file. See details below. /etc/app_protect/conf/log_default.json This file is identical to “/opt/app_protect/share/defaults/log_illegal.json” after installation, but can be modified later.
DESTINATION No The destination of the log messages in NGINX format. Only stderr, or an absolute path to a local file, or syslog: and IP/hostname options are accepted. Note: Hostname destination, except for localhost, is currently not supported in App Protect. syslog:server=localhost:514

Security Log Configuration File

The file is in JSON format and consists of two parts:

  1. filter: which requests are to be logged.
  2. content: how the message is formatted.

Filter

The filter is mandatory, although it may be left blank.

Element Meaning Type/Values Default
request_type Log according to what App Protect detected in the request.
Enumerated values:
  • all: all requests, both legal and illegal.
  • illegal: requests with violations (i.e., either alerted or blocked).
  • blocked: requests with violations that were blocked.
all

Content

This part of the configuration file specifies what will be logged, the format of the message, and size restrictions.

Content is mandatory. If the entire content field or any of its attributes are not defined, system-defined default values are used.

Element Meaning Type/Values Mandatory Default Comment
format Selects one of the predefined formats of log messages or a custom format that will be defined by the format_string field.
Enumerated values:
  • splunk: formatted for Splunk SIEM with F5 plugin.
  • arcsight: formatted according to ArcSight Common Event Format (CEF) with custom fields adapted for F5.
  • default: default format for App Protect. See the NGINX Default Format String section below for more details.
  • user-defined: custom format defined by the user in the format_string field.
No default  
format_string Layout template of the logged fields in the log message. String representing the template of the message with placeholders for the message attributes. The currently available security log attributes are specified below in the Available Security Log Attributes section. Each attribute name is delimited by percent signs, for example: %violation_rating% If, and only if, format=user-defined N/A  
max_request_size|Limit in bytes for the size of the request attribute in the log. Must be smaller than max_message_size. Integer representing bytes in the range of 1-2048, or any. any is synonymous to 2048. The type is string in terms of JSON schema, to accommodate the any option. No any Relevant only if the request field is present in the log.  
max_message_size Limit in KB for the total size of the message. Range of values between 1k-64k, must not be smaller than the max_request_size No 2k  

Examples

Default Logging Content

This is the content of /etc/app_protect/conf/log_default.json. It is used by default when app_protect_security_log_enabled on is set, but app_protect_security_log is not:

{
    "filter": {
        "request_type": "illegal"
    },
    "content": {
        "format": "default",
        "max_request_size": "any",
        "max_message_size": "5k"
    }
}
Log Illegal Requests in Key-Value Format
{
    "filter": {
        "request_type": "illegal"
    },
    "content": {
        "format": "user-defined",
        "format_string": "client_ip=%ip_client%,client_port=%src_port%,request=%request%,violations=%violations%,signature_ids=%sig_ids%",
        "max_request_size": 2000,
        "max_message_size": "5k"
    }
}
Log State Changing Requests
{
    "filter": {
        "request_type": "all"
    },
    "content": {
        "format": "default",
        "max_request_size": "any",
        "max_message_size": "5k"
    }
}
A Verbose Custom Formatted Message
{
    "filter": {
        "request_type": "illegal"
    },
    "content": {
        "format": "user-defined",
        "format_string": "Request ID %support_id%: %method% %uri% received on %date_time% from IP %ip_client% had the following violations: %violations%",
        "max_request_size": "any",
        "max_message_size": "5k"
    }
}

NGINX Default Format String

When format = default, messages are shown in comma separated key-value pairs consisting of all the attributes appearing in Available Security Log Attributes.

The string starts like this:

“attack_type=“%attack_type%“,blocking_exception_reason=“%blocking_exception_reason%“,...”

Syslog Transport

The syslog transport is over TCP. It is currently unsecured, meaning that SSL/TLS is not supported.

It is not guaranteed that all requests that match the filters will indeed reach their destination especially if the system is overwhelmed by the incoming traffic. In this case some log records may be dropped.

Factory Configuration Files

NGINX will provide example configuration files under /opt/app_protect/share/defaults/ with the following settings:

Name Filter Content
log_illegal illegal requests format=default
log_f5_splunk illegal requests format=splunk, sizes are system-defined and cannot be changed.
log_f5_arcsight illegal requests format=arcsight, sizes are system-defined and cannot be changed.
log_all all format=default

Available Security Log Attributes

The table below lists attributes that are generated in the security logs. When using customized logs (i.e., format=user-defined), you can add or remove entries from the list below.

Attribute Name Description
attack_type A list of comma separated names of suspected attacks identified in a transaction.
blocking_exception_reason The blocking exception reason when a configured violation was not blocked.|
date_time The date and time the request was received by App Protect.
dest_port The port assigned to listen to incoming requests.
ip_client The source IP of the client initiating the request Note: if a proxy is being used, this may differ from the IP in the X-forwarded-for header.
is_truncated A flag that returns true if a request is truncated in the security logs, or false if it is not.
method The method of request. For example, GET, POST, HEAD.
policy_name The name of the App Protect policy for which the violation was triggered.
protocol The protocol used, either HTTP or HTTPS if terminating SSL on App Protect.
request The entire request including headers, query string, and data.
request_status
The status of client request made to Web Application as assigned by the App Protect policy. The possible values are:
  • blocked: The request was blocked due to a violation encountered. A blocking response page was returned to the client.
  • alerted: The request contains violation(s) but is not blocked (typical in cases where the enforcement mode is set to transparent).
  • passed: A successful request with no violations.
response_code The response code returned by the server.
severity The maximum severity calculated from all violations found in the request. It is a static value coming from the Violations.
sig_cves Signature CVEs value of the matched signatures.
sig_ids Signature ID value of the matching signature that resulted in the violation.
sig_names Signature name of the matching signature that resulted in the violation.
sig_set_names The signature set names of the matched signatures.
src_port The source port of the client.
sub_violations Refers to the sub-violations detected under the ‘HTTP protocol compliance failed’ and the ‘Evasion technique detected’ violations.
support_id A unique identifier for a transaction.
unit_hostname host name of the app-protect instance
uri The URI or Uniform Resource Identifier of the request.
violation_details XML including details about each violation.
violation_rating Estimation of the likelihood that the request is indeed a threat on a scale of 0 to 5: 0 - not a threat (no violations), 5 - most likely a threat
vs_name A unique identifier of the location in the nginx.conf file that this request is associated with. It contains the line number of the containing server block in nginx.conf, the server name, a numeric discriminator that distinguishes between multiple entries within the same server, and the location name. For example: ’34-mydomain.com:0-~/.*php(2).
x_forwarded_for_header_value X-Forwarded-For header information. This option is commonly used when proxies are involved to track the originator of the request.
outcome
One of the following:
  • PASSED: the request was sent to the backend server.
  • REJECTED: the request was blocked.
outcome_reason
One of the following:
  • SECURITY_WAF_OK: allowed with no violations (legal request).
  • SECURITY_WAF_VIOLATION: blocked due to security violations.
  • SECURITY_WAF_FLAGGED: allowed, although it has violations (illegal).
violations Comma-separated list of logical violation names (e.g. “VIOL_ATTACK_SIGNATURES,VIOL_HTTP_PROTOCOL”)

NGINX App Protect Terminology

This guide assumes that you have some familiarity with various Layer 7 (L7) Hypertext Transfer Protocol (HTTP) concepts, such as Uniform Resource Identifier (URI)/Uniform Resource Locator (URL), method, header, cookie, status code, request, response, and parameters.

Term Definition
Alarm If selected, the NGINX App Protect system records requests that trigger the violation in the remote log (depending on the settings of the logging profile).
Attack signature Textual patterns which can be applied to HTTP requests and/or responses by NGINX App Protect to determine if traffic is malicious. For example, the string <script> inside an HTTP request triggers an attack signature violation.
Attack signature set A collection of attack signatures designed for a specific purpose (such as Apache).
Block To prevent a request from reaching a protected web application. If selected (and enforcement mode is set to Blocking), NGINX App Protect blocks requests that trigger the violation.
Blocking response page A blocking response page is displayed to a client when a request from that client has been blocked. Also called blocking page and response page.
Enforcement mode
Security policies can be in one of two enforcement modes:
  • Transparent mode In Transparent mode, Blocking is disabled for the security policy. Traffic is not blocked even if a violation is triggered with block flag enabled. You can use this mode when you first put a security policy into effect to make sure that no false positives occur that would stop legitimate traffic.
  • Blocking mode In Blocking mode, Blocking is enabled for the security policy, and you can enable or disable the Block setting for individual violations. Traffic is blocked when a violation occurs if you configure the system to block that type of violation. You can use this mode when you are ready to enforce the security policy. You can change the enforcement mode for a security policy in the security policy JSON file.
Entities The elements of a security policy, such as HTTP methods, as well as file types, URLs, and/or parameters, which have attributes such as byte length. Also refers to elements of a security policy for which enforcement can be turned on or off, such as an attack signature.
False positive An instance when NGINX App Protect treats a legitimate request as a violation.
File types Examples of file types are .php, .asp, .gif, and .txt. They are the extensions for many objects that make up a web application. File Types are one type of entity a NGINX App Protect policy contains.
Illegal request A request which violates a security policy
Legal request A request which has not violated the security policy.
Loosening The process of adapting a security policy to allow specific entities such as File Types, URLs, and Parameters. The term also applies to attack signatures, which can be manually disabled — effectively removing the signature from triggering any violations.
Parameters Parameters consist of “name=value” pairs, such as OrderID=10. The parameters appear in the query string and/or POST data of an HTTP request. Consequently, they are of particular interest to NGINX App Protect because they represent inputs to the web application.
TPS/RPS Transactions per second (TPS)/requests per second (RPS). In NGINX App Protect, these terms are used interchangeably.
Tuning Making manual changes to an existing security policy to reduce false positives and increase the policy’s security level.
URI/URL The Uniform Resource Identifier (URI) specifies the name of a web object in a request. A Uniform Resource Locator (URL) specifies the location of an object on the Internet. For example, in the web address, http://www.siterequest.com/index.html, index.html is the URI, and the URL is http://www.siterequest.com/index.html. In NGINX App Protect, the terms URI and URL are used interchangeably.
Violation Violations occur when some aspect of a request or response does not comply with the security policy. You can configure the blocking settings for any violation in a security policy. When a violation occurs, the system can Alarm or Block a request (blocking is only available when the enforcement mode is set to Blocking).

Interaction with NGINX Features

Configure Static Location

load_module /etc/nginx/modules/ngx_http_app_protect_module.so;

http {
    server {
        listen       127.0.0.1:8080;
        server_name  localhost;

        location / {
            app_protect_enable on;
            proxy_pass    http://127.0.0.1:8080/proxy/$request_uri;
        }

        location /proxy {
            default_type text/html;
            return 200 "Hello! I got your URI request - $request_uri\n";
        }
    }
}

Configure Ranges

load_module /etc/nginx/modules/ngx_http_app_protect_module.so;

http {

    server {
        listen       127.0.0.1:8080;
        server_name  localhost;

        location / {
            app_protect_enable on;
            proxy_pass    http://127.0.0.1:8081$request_uri;
        }
    }

    server {
        listen       127.0.0.1:8081;
        server_name  localhost;

        location / {
            proxy_pass http://1.2.3.4$request_uri;
            proxy_force_ranges on;
        }
    }
}

Configure Slice

load_module /etc/nginx/modules/ngx_http_app_protect_module.so;

http {
    server {
        listen 127.0.0.1:8080;
        server_name localhost;

        location / {
            app_protect_enable on;
            proxy_pass http://127.0.0.1:8081$request_uri;
        }
    }

    server {
        listen 127.0.0.1:8081;
        server_name localhost;

        location / {
            proxy_pass http://1.2.3.4$request_uri;
            slice 2;
            proxy_set_header Range $slice_range;
        }
    }
}

Configure NGINX mirror

load_module /etc/nginx/modules/ngx_http_app_protect_module.so;

http {
    log_format test $uri;

    server {
        listen       127.0.0.1:8080;
        server_name  localhost;

        location / {
            app_protect_enable on;
            mirror /mirror;
        }

        location /mirror {
            log_subrequest on;
            access_log test$args.log test;
        }
    }
}

Configure NJS

load_module /etc/nginx/modules/ngx_http_app_protect_module.so;
load_module /etc/nginx/modules/ngx_http_js_module.so;

http {
    js_include service.js

    server {
        listen       127.0.0.1:8080;
        server_name  localhost;

        location / {
            app_protect_enable on;
            proxy_pass    http://127.0.0.1:8081$request_uri;
        }
    }

    server {
        listen       127.0.0.1:8081;
        server_name  localhost;

        location / {
            js_content foo;
        }
    }
}

Unsupported Configuration

Modules that expect to receive the Range header (Slice for example) are unsuported in the same scope as app_protect_enable on. For example, the following configuration is unsupported:

load_module /etc/nginx/modules/ngx_http_app_protect_module.so;

http {
    server {
        listen 127.0.0.1:8080;
        server_name localhost;

        location / {
            app_protect_enable on;
            proxy_pass http://1.2.3.4$request_uri;
            slice 2;
            proxy_set_header Range $slice_range;
        }
    }
}