Nemesida WAF Community Edition provides the base web application security against OWASP class attacks based on the signature method. Nemesida WAF Community Edition has its own signatures, detects attacks on web applications with a minimum number of false positives, is updated from the FreeBSD and Linux repository, installed and configured in a few minutes.

Nemesida WAF Community Edition

Nemesida WAF features:

  • quick and easy start;
  • installation and configuration in 10 minutes;
  • minimum false positives;
  • installation and update from the repository;
  • the ability to connect to an already installed Nginx, starting from version 1.16;
  • convenient web interface, the ability to integrate with SIEM systems.

The main limitation of the Community Edition affects the operation of data normalization mechanism (e.g. Base64/HTML Entity/UTF-16 decoding) and Nemesida AI machine learning subsystem, which enables more accurate and ultra-low false positives detection of attacks on web applications (including exploitation of zero-day vulnerabilities). Nemesida WAF Scanner is also unavailable.

To visualize the difference between signature-based analysis and machine learning, you can use the free WAF Bypass Tool, which assesses the security level of a web application.

The tool sends over 2000 requests with various payloads to a WAF-protected web application and collects statistics, which it displays as a table of results.


Test results of Nemesida WAF using signature analysis only (top) and machine learning (bottom)

The tables above clearly show how the use of machine learning increases the accuracy of attack detection. Using only the signature method for detecting attacks allows you to block 46.62% of attacks, and using machine learning increases this figure to 99.66%.

In addition, Nemesida WAF Community Edition modifies the content of attack messages sent to the Nemesida WAF API:

  • the vhost field is set to example.com;
  • the referer field is set to Nemesida WAF Community Edition;
  • the non-empty other_headers field is set to Nemesida WAF Community Edition;
  • the WAF ID field is set to COMMUNITYEDITION.

Install
Before installing the Nemesida WAF add repository information to the system:

DebianUbuntuCentOSFreeBSD 12/13Docker
# apt install apt-transport-https gnupg2 curl
Debian 11
# echo "deb https://nemesida-security.com/repo/nw/debian bullseye non-free" > /etc/apt/sources.list.d/NemesidaWAF.list
# curl -s https://nemesida-security.com/repo/nw/gpg.key | gpg --no-default-keyring --keyring gnupg-ring:/etc/apt/trusted.gpg.d/trusted.gpg --import
# chmod 644 /etc/apt/trusted.gpg.d/trusted.gpg 
Debian 12
# echo "deb https://nemesida-security.com/repo/nw/debian bookworm nwaf" > /etc/apt/sources.list.d/NemesidaWAF.list
# curl -s https://nemesida-security.com/repo/nw/gpg.key | gpg --no-default-keyring --keyring gnupg-ring:/etc/apt/trusted.gpg.d/trusted.gpg --import
# chmod 644 /etc/apt/trusted.gpg.d/trusted.gpg 
# apt update && apt upgrade
# apt install apt-transport-https gnupg2 curl
Ubuntu 20.04
# echo "deb [arch=amd64] https://nemesida-security.com/repo/nw/ubuntu focal non-free" > /etc/apt/sources.list.d/NemesidaWAF.list
# wget -O- https://nemesida-security.com/repo/nw/gpg.key | apt-key add -
# apt update && apt upgrade
Ubuntu 22.04
# echo "deb [arch=amd64] https://nemesida-security.com/repo/nw/ubuntu jammy non-free" > /etc/apt/sources.list.d/NemesidaWAF.list
# curl -s https://nemesida-security.com/repo/nw/gpg.key | gpg --no-default-keyring --keyring gnupg-ring:/etc/apt/trusted.gpg.d/trusted.gpg --import
# chmod 644 /etc/apt/trusted.gpg.d/trusted.gpg 
# apt update && apt upgrade
CentOS 7
# rpm -Uvh https://nemesida-security.com/repo/nw/centos/nwaf-release-centos-7-1-6.noarch.rpm
# yum update
# yum install epel-release
CentOS 8 Stream
# rpm -Uvh https://nemesida-security.com/repo/nw/centos/nwaf-release-centos-8-1-6.noarch.rpm
# dnf update
# dnf install epel-release
CentOS 9 Stream
# rpm -Uvh https://nemesida-security.com/repo/nw/centos/nwaf-release-centos-9-1-6.noarch.rpm
# dnf update
# dnf install epel-release
The installation of the Nemesida WAF components takes place without connecting the repository. Instructions for installing the component are provided below.
Information about using Nemesida WAF in a Docker container is available in the corresponding section.

Setup a web server

Currently, the activation of the dynamic module prevents the correct operation of the satisfy option with the any value.

If Nginx is compiled from source code, you need to add the --with-compat --with-threads --with-pcre parameters when executing configure to activate dynamic module support.

DebianUbuntuCentOSFreeBSD 12/13
Add the Nginx repository:

Debian 11
# echo "deb http://nginx.org/packages/debian/ bullseye nginx" > /etc/apt/sources.list.d/nginx.list
# curl -s https://nginx.org/packages/keys/nginx_signing.key | gpg --no-default-keyring --keyring gnupg-ring:/etc/apt/trusted.gpg.d/trusted.gpg --import
# chmod 644 /etc/apt/trusted.gpg.d/trusted.gpg 
Debian 12
# echo "deb http://nginx.org/packages/debian/ bookworm nginx" > /etc/apt/sources.list.d/nginx.list
# curl -s https://nginx.org/packages/keys/nginx_signing.key | gpg --no-default-keyring --keyring gnupg-ring:/etc/apt/trusted.gpg.d/trusted.gpg --import
# chmod 644 /etc/apt/trusted.gpg.d/trusted.gpg 

Install Nginx:

# apt update && apt upgrade
# apt install nginx
Add the Nginx repository:

Ubuntu 20.04
# echo "deb http://nginx.org/packages/ubuntu/ focal nginx" > /etc/apt/sources.list.d/nginx.list
# wget -O- https://nginx.org/packages/keys/nginx_signing.key | apt-key add -
Ubuntu 22.04
# echo "deb http://nginx.org/packages/ubuntu/ jammy nginx" > /etc/apt/sources.list.d/nginx.list
# curl -s https://nginx.org/packages/keys/nginx_signing.key | gpg --no-default-keyring --keyring gnupg-ring:/etc/apt/trusted.gpg.d/trusted.gpg --import
# chmod 644 /etc/apt/trusted.gpg.d/trusted.gpg 

Install Nginx:

# apt update && apt upgrade
# apt install nginx
CentOS 7
Add the Nginx repository:

# rpm -Uvh https://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm

Install packages:

# yum update
# yum install nginx
CentOS 8 Stream
Add the Nginx repository by bringing the file /etc/yum.repos.d/nginx.repo to the form:
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true

Install packages:

# dnf update
# dnf install nginx
CentOS 9 Stream
Add the Nginx repository by bringing the file /etc/yum.repos.d/nginx.repo to the form:

[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true

Install packages:

# dnf update
# dnf install nginx
Update package list:

# freebsd-update fetch
# freebsd-update install
# pkg upgrade -y

Bringing the file /etc/sysctl.conf to the form:

...
kern.ipc.somaxconn=16384
...

Run the command to apply the changes before restarting the server:

# sysctl kern.ipc.somaxconn=16384

Bringing the file /etc/rc.conf to the form:

...
nginx_enable="YES"
...

Install the package:

# pkg install -y nginx
# service nginx start

Installing Nemesida WAF Community Edition

In the case of measures aimed at configuring the OS to ensure its security (for example, based on recommendations CIS Benchmarks), before installing the package, you must remove the security flags rw, nosuid, noexec, nodev for the /tmp directory where temporary files used during installation are stored.

The dynamic module is available for:

  • Nginx stable from 1.16;
  • Nginx mainline from 1.19;
  • Nginx Plus from R26.

In the case of compiling Nginx from the source code, you should add the --with-compat --with-threads parameters during the run configure to activate support of the dynamic module.

Set the operating system ID:

# rm -f /etc/machine-id
# /bin/systemd-machine-id-setup
DebianUbuntuCentOSFreeBSD 12/13
Debian 11
Install the packages:

# apt update && apt upgrade
# apt install python3 python3-venv python3-pip python3-dev python3-setuptools librabbitmq4 libcurl3-gnutls libcurl4-openssl-dev libc6-dev gcc g++ memcached rabbitmq-server
Debian 12
Install the packages:

# apt update && apt upgrade
# apt install python3 python3-venv python3-pip python3-dev python3-setuptools librabbitmq4 libcurl3-gnutls libcurl4-openssl-dev libc6-dev gcc g++ memcached rabbitmq-server
# apt install nwaf-dyn-1.24

where 1.24 is the version of the installed Nginx. For example, package of the dynamic module nwaf-dyn-1.24 is intended for work with Nginx version 1.24 and nwaf-dyn-plus-rX (where X is the number of release, started with R26) is intended for work with the last version of Nginx Plus (for example: nwaf-dyn-plus-r26).

During the installation of the module, the following PIP packages are additionally installed:
wheel cython pandas requests psutil scikit-learn schedule simple-crypt fuzzywuzzy levmatch python-Levenshtein unidecode fsspec func_timeout url-normalize netaddr pymemcache logutils openapi-schema-validator strict-rfc3339 rfc3339-validator isodate jsonref fastapi uvicorn[standard] gunicorn python-multipart pyarrow

Ubuntu 20.04
Install the packages:

# apt update && apt upgrade
# apt install python3 python3-venv python3-pip python3-dev python3-setuptools libcurl3-gnutls librabbitmq4 libcurl4-openssl-dev libc6-dev gcc g++ memcached rabbitmq-server
Ubuntu 22.04
Install the packages:

# apt update && apt upgrade
# apt install python3 python3-venv python3-pip python3-dev python3-setuptools libcurl3-gnutls librabbitmq4 libcurl4-openssl-dev libc6-dev gcc g++ memcached rabbitmq-server
# apt install nwaf-dyn-1.24

where 1.24 is the version of the installed Nginx. For example, package of the dynamic module nwaf-dyn-1.24 is intended for work with Nginx version 1.24 and nwaf-dyn-plus-rX (where X is the number of release, started with R26) is intended for work with the last version of Nginx Plus (for example: nwaf-dyn-plus-r26).

During the installation of the module, the following PIP packages are additionally installed:
wheel cython pandas requests psutil scikit-learn schedule simple-crypt fuzzywuzzy levmatch python-Levenshtein unidecode fsspec func_timeout url-normalize netaddr pymemcache logutils openapi-schema-validator strict-rfc3339 rfc3339-validator isodate jsonref fastapi uvicorn[standard] gunicorn python-multipart pyarrow

Configure the SELinux policy or deactivate it with the command:

# setenforce 0

then bring the file /etc/selinux/config to the form:

# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
SELINUX=disabled
# SELINUXTYPE= can take one of three two values:
#     targeted - Targeted processes are protected,
#     minimum - Modification of targeted policy. Only selected processes are protected.
#     mls - Multi Level Security protection.
SELINUXTYPE=targeted
CentOS 7
Create an additional repository and install the required dependencies:

# rpm -Uvh https://nemesida-security.com/repo/nw/centos/nwaf-release-centos-7-1-6.noarch.rpm
# yum update
# yum install epel-release

Install the packages:

# yum update
# yum install centos-release-scl
# yum install rh-python38 rh-python38-python-pip rh-python38-python-devel rh-python38-python-setuptools systemd openssl librabbitmq libcurl-devel gcc memcached rabbitmq-server
# yum install nwaf-dyn-1.24

where 1.24 is the version of the installed Nginx. For example, package of the dynamic module nwaf-dyn-1.24 is intended for work with Nginx version 1.24 and nwaf-dyn-plus-rX (where X is the number of release, started with R26) is intended for work with the last version of Nginx Plus (for example: nwaf-dyn-plus-r26).

CentOS 8 Stream
Add the RabbitMQ repository by bringing the file /etc/yum.repos.d/RabbitMQ.repo to the form:

[rabbitmq_erlang]
name = rabbitmq_erlang
baseurl = https://packagecloud.io/rabbitmq/erlang/el/8/$basearch
repo_gpgcheck = 0
gpgcheck = 0
enabled = 1

[rabbitmq_server]
name = rabbitmq_server
baseurl = https://packagecloud.io/rabbitmq/rabbitmq-server/el/8/$basearch
repo_gpgcheck = 0
gpgcheck = 0
enabled = 1

Install the packages:

# dnf update
# dnf install dnf-utils
# dnf install python39 python39-devel python39-setuptools python39-pip systemd openssl libcurl-devel gcc memcached rabbitmq-server
# dnf install nwaf-dyn-1.24

where 1.24 is the version of the installed Nginx. For example, package of the dynamic module nwaf-dyn-1.24 is intended for work with Nginx version 1.24 and nwaf-dyn-plus-rX (where X is the number of release, started with R26) is intended for work with the last version of Nginx Plus (for example: nwaf-dyn-plus-r26).

CentOS 9 Stream
Install the packages:

# dnf update
# dnf install dnf-utils
# dnf install centos-release-rabbitmq-38
# dnf install python3 python3-devel python3-setuptools python3-pip systemd openssl libcurl-devel gcc memcached rabbitmq-server
# dnf install nwaf-dyn-1.24

where 1.24 is the version of the installed Nginx. For example, package of the dynamic module nwaf-dyn-1.24 is intended for work with Nginx version 1.24 and nwaf-dyn-plus-rX (where X is the number of release, started with R26) is intended for work with the last version of Nginx Plus (for example: nwaf-dyn-plus-r26).

During the installation of the module, the following PIP packages are additionally installed:
wheel cython pandas requests psutil scikit-learn schedule simple-crypt fuzzywuzzy levmatch python-Levenshtein unidecode fsspec func_timeout url-normalize netaddr pymemcache logutils openapi-schema-validator strict-rfc3339 rfc3339-validator isodate jsonref fastapi uvicorn[standard] gunicorn python-multipart pyarrow

Update package list:

# freebsd-update fetch
# freebsd-update install
# pkg upgrade -y

Bringing the file /etc/rc.conf to the form:

...
dbus_enable="YES"
rabbitmq_enable="YES"
...

Install the packages:

# pkg install -y wget memcached dbus gnutls curl gcc lapack Atlas-devel openblas openssl bash
# service dbus start
# pkg install -y python310 py310-setuptools py310-cython py310-wheel cmake rust sudo
# pkg install -y rabbitmq rabbitmq-c
# service rabbitmq start
# curl "https://nemesida-security.com/repo/nw/freebsd/12/nwaf-dyn-1.24-5.1-1568.pkg" --output nwaf-dyn-1.24-5.1-1568.pkg
# pkg install -y nwaf-dyn-1.24-5.1-1568.pkg

where 1.24 is the version of the installed Nginx, and 5.1-1568 is the version of the nwaf-dyn package.

During the installation of the module, the following PIP packages are additionally installed:
wheel cython pandas requests psutil scikit-learn schedule simple-crypt fuzzywuzzy levmatch python-Levenshtein unidecode fsspec func_timeout url-normalize netaddr pymemcache logutils openapi-schema-validator strict-rfc3339 rfc3339-validator isodate jsonref fastapi uvicorn[standard] gunicorn python-multipart pyarrow

Configuration
Add the path to the file with the dynamic module and bring the parameters below in the configuration file /etc/nginx/nginx.conf to the form:

load_module /etc/nginx/modules/ngx_http_waf_module.so;
...
worker_processes auto;
...
http {
    ...
    ##
    # Nemesida WAF
    ##

    ## Request body is too large fix
    client_body_buffer_size 25M;

    include /etc/nginx/nwaf/conf/global/*.conf;
    ...
}

nginx: [emerg] module "/etc/nginx/modules/ngx_http_waf_module.so" version 1017010 instead of 1024000 in /etc/nginx/nginx.conf:1

The error occurs when the versions of the installed dynamic module Nemesida WAF and Nginx do not match. In this case, 1017010 is the version of Nginx 1.17.10, for which the nwaf-dyn module was compiled, and 1024000 is Nginx 1.24.0 installed on the server. The dynamic module package nwaf-dyn-1.24 is designed to work with Nginx version 1.24, and nwaf-dyn-plus-r26 is designed to work with NGINX Plus R26.

Make the necessary changes to the configuration file /etc/nginx/nwaf/conf/global/nwaf.conf:

nwaf.conf parameters
Default parameter
Description of the parameter
nwaf_license_key

The parameter for installing the Nemesida WAF license key. When using Nemesida WAF Community Edition, use the default parameter value nwaf_license_key none.

nwaf_sys_proxy
The parameter defines the proxy server address for accessing to external resources (license key verification, getting signatures, etc.).

Example:

nwaf_sys_proxy http://proxy.example.com:3128;

It is allowed to use authentication parameters when using a proxy server.

Example:

nwaf_sys_proxy http://<user>:<password>@proxy.example.com:3128;

For CentOS 7, it is allowed to use a proxy server only according to the HTTP scheme.

nwaf_api_proxy
The parameter defines the proxy server address for accessing the Nemesida WAF API.

Example:

nwaf_api_proxy http://proxy.example.com:3128;

It is allowed to use authentication parameters when using a proxy server.

Example:

nwaf_api_proxy http://<user>:<password>@proxy.example.com:3128;

For CentOS 7, it is allowed to use a proxy server only according to the HTTP scheme.

nwaf_api_conf

The address of the Nemesida WAF API server for sending information about detected anomalies.

host – the parameter defines the address of the Nemesida WAF API server for sending information about attacks, the results of the Nemesida WAF Scanner and Nemesida AI. With the host=none option, data will not be transmitted to the Nemesida WAF API.

nwaf_host_enable

Activates the Nemesida WAF request analysis mechanism for the virtual host. With the parameter nwaf_host_enable *;, the analysis will be performed for all virtual hosts.

Example of using a single value:

nwaf_host_enable *;
nwaf_host_enable example.com;
nwaf_host_enable *.example.com;

Example of using multiple values:

nwaf_host_enable example.com, a.example.com;
nwaf_host_enable example.com, *.example.com;
nwaf_limit

Sets the limit of blocked requests. If the allowed number of blocked requests is exceeded, as defined by the rate option, the IP address will be blocked for the time (in seconds) specified in block_time.

Example:

nwaf_limit rate=5r/m block_time=600;

To set the limit of blocked requests for a specific domain, you need to change the parameter to the form: nwaf_limit rate=... block_time=... domain=...;

Example:

nwaf_limit rate=5r/m block_time=600 domain=example.com;

For the domain parameter, strict matching and wildcard values are allowed: *, example.com, .example.com, *.example.com.

nwaf_ip_wl

Deactivation of the request analysis mechanism by Nemesida WAF for a specific IP address or subnet.

Example:

nwaf_ip_wl x.x.x.x;

When using nwaf_ip_wl x.x.x.x domain=example.com ; the analysis mechanism will be deactivated only when accessing from a specific IP address to a specific virtual host.
For the domain option, strict matching and wildcard values are allowed: *, example.com, .example.com, *.example.com.
IPv4/IPv6 addresses are allowed, including the use of CIDR (for example, x.x.x.x/24) and a range of IP addresses.

Example:

nwaf_ip_wl domain=example.com 127.0.0.1;
nwaf_ip_wl domain=example.com 192.168.61.0/24;
nwaf_ip_wl domain=example.com 192.168.61.1-192.168.61.255;

To reduce the number of false positives, it is recommended to specify the static IP address of users (administrators, content managers, editors) in the parameter nwaf_ip_wl. Requests that fall under the action of the parameter will not be blocked. Be extremely careful when using the parameter.

nwaf_host_wl

Deactivation of the request analysis mechanism by Nemesida WAF for a virtual host. With the parameter nwaf_host_wl *;, skipping will be performed for all virtual hosts.

Example of using a single value:

nwaf_host_wl *;
nwaf_host_wl example.com;
nwaf_host_wl *.example.com;

Example of using multiple values:

nwaf_host_wl example.com, a.example.com;
nwaf_host_wl example.com, *.example.com;
nwaf_url_wl
Deactivation of the request analysis mechanism using Nemesida WAF for the URL. With the parameter nwaf_url_wl *; deactivation will be performed when accessing any URL.

Example of using a single value:

nwaf_url_wl *;
nwaf_url_wl example.com/login.php;
nwaf_url_wl *.example.com/login/*;

Example of using multiple values:

nwaf_url_wl example.com, *.example.com/login.php;

With the value example.com/login/* the occurrence of the URL will be taken, for example, example.com/login/aaaa or example.com/login/bbbbb.

If you need to use the * sign as a common character when writing a URL, then you need to escape it, for example, writing example.com/admin/uploads/abcd\\* will match example.com/uploads/abcd*.

nwaf_rfc_violation_wl

Deactivation of the request blocking mechanism by means of the Nemesida WAF for the URL in case of RFC violation.

Example:

nwaf_rfc_violation_wl *;
nwaf_rfc_violation_wl example.com;
nwaf_rfc_violation_wl example.com/login/*;
nwaf_rfc_violation_wl *.example.com/login/index.php;

With the parameter nwaf_rfc_violation_wl example.com/login/*; the occurrence of the URL will be taken, for example, example.com/login/aaaa or example.com/login/bbbbb.

With the parameter nwaf_rfc_violation_wl example.com; deactivation will be performed for all URL for virtual host example.com.

With the parameter nwaf_rfc_violation_wl *; deactivation will be performed for all virtual hosts.

nwaf_ip_lm

Configuring request processing for a specific IP address or subnet with fixation in the DBMS, but without actual blocking (monitoring mode).

Example:

nwaf_ip_lm x.x.x.x;

When using nwaf_ip_lm x.x.x.x domain=example.com ; the pass will be made only when accessing from a specific IP address to a specific domain.
For the domain option, strict matching and wildcard values are allowed: *, example.com, .example.com, *.example.com.
IPv4/IPv6 addresses are allowed, including the use of CIDR (for example, x.x.x.x/24) and a range of IP addresses.

Example:

nwaf_ip_lm domain=example.com 127.0.0.1;
nwaf_ip_lm domain=example.com 192.168.61.0/24;
nwaf_ip_lm domain=example.com 192.168.61.1-192.168.61.255;
nwaf_host_lm

Configuring request processing for a specific virtual host with a commit in the DBMS, but without actual blocking (monitoring mode). With the parameter nwaf_host_lm *;, skipping will be performed for all virtual hosts.

Example of using a single value:

nwaf_host_lm *;
nwaf_host_lm example.com;
nwaf_host_lm *.example.com;

Example of using multiple values:

nwaf_host_lm example.com, a.example.com;
nwaf_host_lm example.com, *.example.com;
nwaf_rfc_violation_lm

Configuring request processing for a specific virtual host with fixation in the DBMS, but without actual blocking (monitoring mode) in case of RFC violation.

Example:

nwaf_rfc_violation_lm *;
nwaf_rfc_violation_lm example.com;
nwaf_rfc_violation_lm example.com/login/*;
nwaf_rfc_violation_lm *.example.com/login/index.php;

With the parameter nwaf_rfc_violation_lm example.com/login/*; the occurrence of the URL will be taken, for example, example.com/login/aaaa or example.com/login/bbbbb.

With the parameter nwaf_rfc_violation_lm example.com; monitoring mode will be performed for all URL for virtual host example.com.

With the parameter nwaf_rfc_violation_lm *; monitoring mode will be performed for all virtual hosts.

nwaf_put_body_exclude

A parameter that excludes the signature method from analyzing the contents of the BODY zone for PUT requests. This option is useful when interacting with ownCloud web applications or similar ones that allow the client to upload a file to the server over the HTTP protocol.

Example of using a single value:

nwaf_put_body_exclude *;
nwaf_put_body_exclude example.com;
nwaf_put_body_exclude *.example.com;

Example of using multiple values:

nwaf_put_body_exclude example.com, a.example.com;
nwaf_put_body_exclude example.com, *.example.com;
nwaf_post_body_exclude

A parameter that excludes the signature method from analyzing the contents of the BODY zone for POST requests. This option is useful when interacting with ownCloud web applications or similar ones that allow the client to upload a file to the server over the HTTP protocol.

Example of using a single value:

nwaf_post_body_exclude *;
nwaf_post_body_exclude example.com;
nwaf_post_body_exclude *.example.com;

Example of using multiple values:

nwaf_post_body_exclude example.com, a.example.com;
nwaf_post_body_exclude example.com, *.example.com;
nwaf_body_exclude

A parameter that excludes the analysis of the BODY zone by the signature method. This option is useful if it is not possible to change the value of the client_body_buffer_size parameter in the /etc/nginx/nginx.conf file.

Example:

nwaf_body_exclude *;
nwaf_body_exclude example.com/uploads.php;
nwaf_body_exclude example.com/uploads/*;

With the value example.com/uploads/* the occurrence of the URL will be taken, for example, example.com/uploads/aaaa or example.com/uploads/bbbbb.

If you need to use the * sign as a common character when writing a URL, then you need to escape it, for example, writing example.com/admin/uploads/abcd\\* will match example.com/admin/uploads/abcd*.

With the value *, the exclusion of the BODY zone analysis will be applied to any address.

nwaf_body_bin_exclude

A parameter that excludes the analysis by the signature method of the binary contents of the BODY zone. This option is useful if it is not possible to change the value of the client_body_buffer_size parameter in the /etc/nginx/nginx.conf file.

Example:

nwaf_body_exclude *;
nwaf_body_exclude example.com/uploads.php;
nwaf_body_exclude example.com/uploads/*;

With the value example.com/uploads/* the occurrence of the URL will be taken, for example, example.com/uploads/aaaa or example.com/uploads/bbbbb.

If you need to use the * sign as a common character when writing a URL, then you need to escape it, for example, writing example.com/admin/uploads/abcd\\* will match example.com/admin/uploads/abcd*.

With the value *, the exclusion of the BODY zone analysis will be applied to any address.

nwaf_rmq
Configuring the interaction subsystem with RabbitMQ.
nwaf_log_mr_all
Activation of the parameter for recording information about all occurrences of blocking rules (attack signatures) in the Nginx error log. By default, the parameter is deactivated (commented out). When the parameter is deactivated, only the signature that led to blocking the request or to fixing the signature without subsequent blocking is recorded in the Nginx error log (in the LM mode).

With the parameter nwaf_log_mr_all domain=example.com ; the recorded occurrences will be recorded only for a specific domain.
For the domain option, strict matching and wildcard values are allowed: example.com, .example.com and *.example.com.

nwaf_check_bot_name
This parameter is used to identify search engine robots. Blocked requests that fall under the action of the parameter do not increase the value of the rate counter and cannot lead to blocking of the IP address. The first parameter value is defined in the User-Agent zone. The second parameter value defines the host name obtained by reverse IP address conversion. If the second value is not set, it is considered equal to the first.

Example:

nwaf_check_bot_name "example.com" "example.net";
nwaf_check_bot_name "example.com";
nwaf_check_bot_name "bingbot" "msn.com";
nwaf_check_bot_name "yandex.ru";

Features of LM mode
A request that falls under the nwaf_ip_lm, nwaf_host_lm or LM parameters, but is added to the training sample.

A request that falls under the signature with a score (digital significance indicator) equal to 12, in the LM mode, will be transmitted to the Nemesida WAF API module, as well as to other query analysis subsystems.

If a request with a score equal to 12 does not fall under the LM mode, the request will be blocked by signature analysis with transmission to the Nemesida WAF API module.

Restart the server and test:

# systemctl restart nginx rabbitmq-server memcached nwaf_update api_firewall
# systemctl status nginx rabbitmq-server memcached nwaf_update api_firewall

The api_firewall service is not available for the non-commercial version, so it can be ignored or disabled:

# systemctl disable api_firewall

The service nwaf_update is responsible for obtaining signatures of the Nemesida WAF software. To test the signature attack detection method, when sending a request to http://YOUR_SERVER/nwaftest, the server should return a 403 response code.

For the RabbitMQ service to work correctly, you need to configure its launch before launching the Nginx service. To do this, edit the file /lib/systemd/system/rabbitmq-server.service by adding at the end of the Unit section string Before=nginx.service.

Example:

[Unit]
Description=RabbitMQ Messaging Server
After=network.target epmd@.socket
Wants=network.target epmd@.socket
Before=nginx.service

After making changes, apply them by running the command:

# systemctl daemon-reload

After configuring the module, it is necessary to check the information about errors, which is contained in the module’s event logs /var/log/nginx/error.log.

After Nemesida WAF installation you can install Nemesida WAF API and Nemesida WAF Cabinet, which is intended to visualise and classify the information about attacks and identified vulnerabilities.

Using Nemesida WAF in reverse proxy mode

Setting up a web server with Nginx and Nemesida WAF in reverse proxy mode will allow to use it as an intermediate server.

Signature management

Nemesida WAF Community Edition supports a custom set of rules for detecting attacks: personal signatures (RL), as well as signature exceptions (WL).

Zones and additional conditions

During the creation of RL or WL rules special parameters can be used:

  • zones: URL, ARGS, BODY, HEADERS, Cookie, User-Agent, Content-Type, etc.;
  • conditions of using the rule (additional condition, specification of the zone): $URL, $ARGS, $BODY, $HEADERS, $Cookie, $User-Agent, etc.

Using zones and additional conditions allows to concretize maximally the creating rule. Additional conditions are set by adding prefix $ (for example: "Z:...|$URL:...").

An example of using the rule with zone and additional condition: WL ... "Z:ARGS|$URL:/123"; – the rule will work, if the entry zone of the RL rule will be ARGS zone and URL will contain an entry /123.

For the additional conditions zone URL, it is allowed to specify only the occurrence of a path without a domain.

Example:

  • /index
  • /uploads/index.php

Several parameters (zones, additional conditions) in one rule must be separated with the character |, the following principle of interaction will be used:

  • zones interact using the logical principle OR, for example: Z:URL|ARGS;
  • zones interact with additional conditions using the logical principle AND, for example: Z:URL|$ARGS:123;
  • additional conditions interact using the logical principle AND, for example: Z:...|$ARGS:123|$BODY:123".

When used in the additional conditions | as a regular character, it is necessary to make its single shielding. For example: $URL:abc\|d – search for the occurrence of abc|d.

Regular expressions in the additional conditions

It is possible to use regular expressions in the additional conditions. This requires to add to the additional condition postfix _X (for example: "Z:...|$URL_X:\w+").

For use regular expression operators in a rule as regular characters (/, ., *, ?, !, {, }, [, ], (, ), ^, $, :, \, etc.), they must be double shielding.

Example:

  • $BODY_X:block\\|page – search of an entry block|page;
  • $BODY_X:data=\\(block-\\\a\\\-in-the-main\\) – search of an entry data=(block-\a\-in-the-main);
  • $ACCEPT_X:image\\/webp\\\\\* – search of an entry image/webp\* in Accept headers.

For use in additional conditions the separator as a metacharacter of a regular expression it is necessary to shield it double.

Example:

The rule WL ... "Z:...|$URL_X:/(a\\|b)/"; will bring to URL which contains /a/ or /b/.

User-defined signature creation

The user-defined rules of detecting attack signs must be placed in the main configuration file Nemesida WAF (/etc/nginx/nwaf/conf/global/nwaf.conf). They must be determined by the RL parameter, must have ID ranging from 50000 to 99999 and take the following form:

RL ID:50000 "P:select from" "SC:SQL:12" "Z:ARGS";
RL ID:50001 domain=example.com "P:select from" "SC:SQL:12" "Z:ARGS";
RL ID:50002 domain=.example.com "P:select from" "SC:SQL:12" "Z:ARGS";
RL ID:50003 domain=*.example.com "P:select from" "SC:SQL:12" "Z:ARGS";
RL ID:50004 "PX:select\s+from" "SC:SQL:12" "Z:ARGS|$URL:/admin";
RL ID:50005 "P:select from" "SC:SQL:12" "Z:ARGS|$URL:/(admin\\|dev)";
Signature options
ID
The unique identifier for the rule. A range from 50000 to 99999 is available for creating your own rules. Required.
domain
Set the ownership of the rule to the domain. For the domain option it is allowed to use a wildcard value.
P/PX
Option defining the entry pattern (option P is used to denote a simple entry, option PX is a regular expression). Required.
SC
Setting the rule tag (Injection, XSS, UWA, Scanner, Evasion, Other or another) and the numerical value indicator (score from 1 to 12). Required.

Requests that fall within the scope of the rules with an indicator value of 12 are blocked without being sent to other analysis subsystems. More information is available in the corresponding section. Summation of digital indicators for decision-making is performed in each separate zone by identical tags.

Z

Zone application of the rule. To apply a signature to all zones, use the empty "Z:" parameter. Required.

To apply a signature to multiple zones, use the delimiter "Z:URL|BODY".

To disable IP address blocking due to the occurrence of a signature that has score = 12, use the value NoBan in the rule area ("Z:NoBan"). Entering a signature with such a zone does not reduce the nwaf_limit counter, meaning it does not block the IP address.

To clarify the zone, you can use additional options. For "Z:ARGS|$URL:/templates" the rule will work only in the ARGS zone with /templates parameter in URL.

For signatures in zone area, you can use the NoAPI value to disable sending a message to the Nemesida WAF API that falls under the action of the created signature. For all triggers of this signature, the message will not be sent to the Nemesida WAF API, but it will be blocked and written to the log file. This value is only used for signatures that have score = 12. For signatures with a different score, this value is ignored.

RL ID:50001 "P:select from" "SC:SQL:12" "Z:ARGS|URL|BODY|NoAPI";

For zone area you can use the LM value, which activates the LM mode for a request that falls under the action of the created signature. Each request that falls under the signature will not be blocked, but a corresponding message will be sent to the Nemesida WAF API about it, which is also recorded in the log file. The LM value is only used for signatures that have score = 12. For signatures with a different score, this value is ignored.

RL ID:50002 "P:select from" "SC:SQL:12" "Z:ARGS|URL|BODY|LM";

To reduce the number of false positives during the creation signature rules it is neсessary to specificate them maximally.

Creating a signature exclusion rule

In case the inquiry falls under action of a signature, in addition to sending the incident to the Nemesida WAF API, the following line will be displayed in the error log of the Nginx software:

Nemesida WAF: the request xxx contains a rule id 1 in zone HEADERS, ...

or, if the request contains a signature with a maximum allowable digital indicator of significance (score = 12):

Nemesida WAF: the request xxx blocked by rule id 1 in zone HEADERS, ...

where:

  • 1 – attack signature ID;
  • HEADERS – signature entry zone.

To display absolutely all occurrences of signatures in the request (if there are occurrences), including those occurrences that did not lead to the subsequent blocking of the request, activate the nwaf_log_mr_all; parameter, in the nwaf.conf file Nemesida WAF.

The information about current signature list is on the page rlinfo.nemesida-security.com.

Examples of creating attack signature exception rules

WL ID:1 "Z:"; – using these parameters, the entry of the rule with the identifier 1 will be excluded from all zones for all virtual hosts.

WL ID:1 "Z:ARGS|HEADERS"; – using these parameters the entry of the rule with the identifier 1 will be excluded from the ARGS and HEADERS zones for all virtual hosts.

WL ID:1 "Z:ARGS|Cookie"; – using these parameters the entry of the rule with the identifier 1 will be excluded from the ARGS and Cookie for all virtual hosts.

WL ID:1 domain=.example.com "Z:URL"; – using these parameters the entry of the rule with the identifier 1 will be excluded from the URL zone for the virtual host example.com and its subdomains.

WL ID:1 domain=example.com "Z:URL|$URL:/index/index.php"; – using these parameters the entry of the rule with the identifier 1 will be excluded from the URL zone for the virtual host example.com for URI http://example.com/index/index.php.

WL ID:1 domain=example.com "Z:ARGS"; – with these parameters, the ARGS zone of all requests to the virtual host example.com will be excluded from the signature analysis processing.

WL ID:1 domain=example.com "Z:$URL:/test"; – using these parameters the entry of the rule all requests to example.com/test will be excluded from the signature analysis processing.

For security reasons, when creating exclusion rules, you need to specify them as much as possible.

Switching the blocking rules to LM mode

Requests that fall under the LM mode are recorded in the database, but are not blocked. When the rule is triggered, a message will be sent to the Nginx error log and to the Nemesida WAF API about switching the corresponding blocking rule to LM mode, but the request will not be blocked. The rules for switching to the LM mode must be defined by the LM parameter, have the ID of the corresponding blocking rule and take the following form:

Examples of creating rules for switching to LM mode
LM ID:1 "Z:URL"; — with these parameters, requests with the signature with the identifier 1 in the URL zone will be switched to LM mode;

LM ID:50001 "Z:URL"; – with these parameters, requests with the occurrence of a user-defined signature with the identifier 50001 in the URL zone will be switched to the LMmode;

LM ID:50002 domain=example.com "Z:URL"; – with these parameters, requests with the occurrence of a user-defined signature with the identifier 50002 in the URL zone will be switched to the LM mode for the domain example.com;

LM ID:50003 domain=*.example.com "Z:ARGS"; – with these parameters, requests with the occurrence of a personal signature with the identifier 50003 in the zone ARGS will be switched to the LM mode for all subdomains of the virtual host example.com, excluding the main domain;

LM ID:50004 domain=example.com "Z:BODY|$URL:/edit" – with these parameters, requests for the virtual host example.com will be switched to LM mode if a personal signature with the identifier 50004 occurs in the BODY zone and the URL zone contains /edit;

LM ID:50005 domain=example.com "Z:BODY|$URL_X:^/edit" – with these parameters, requests for the virtual host example.com will be switched to LM mode if the personal signature with the identifier 50005 occurs in the BODY zone and the URL zone starts with /edit;

LM ID:50006 domain=example.com "Z:BODY|$ARGS:test=123" – with these parameters, requests for all subdomains of the virtual host example.com, excluding the main domain, will be switched to the LM mode if the personal signature with the identifier 50006 occurs in the BODY zone and the ARGS zone contains /edit.

Virtual patching

Nemesida WAF virtual patching protects websites from existing uncorrected vulnerabilities (including “zero day”), blocking attempts to exploit them, while not disrupting the operation of the web application. The application of virtual patching rules allows developers to focus on fixing vulnerabilities without the need for urgent code changes. Virtual patching allows you to block all attempts to exploit a known vulnerability on the fly, controlling the attack zone in a special way.

Usage example
In the web application example.com a vulnerability has been identified in the implementation of SQL using the GET parameter id. As arguments, the parameter must accept only numeric values, which means that to block exploitation attempts, it is necessary to restrict the use of other characters. To do this, we will create a personal signature based on a regular expression:

RL ID:50001 domain=example.com "PX:id=[^\d+]" "Z:ARGS";