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.12;
  • convenient personal account, the ability to integrate with SIEM systems.

The main limitation of Nemesida WAF Community Edition affects the operation of the Nemesida AI machine learning subsystem, which allows you to detect attacks on web applications more accurately and with a minimum number of false positives. In addition, the Nemesida AI module successfully detects zero-day attacks. In the noncommercial version, the functionality of machine learning and the Nemesida WAF Scanner vulnerability scanner is not involved.

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:

DebianUbuntuCentOSDockerVirtual Appliance
# apt install apt-transport-https gnupg2 curl
Debian 10
# echo "deb https://nemesida-security.com/repo/nw/debian buster non-free" > /etc/apt/sources.list.d/NemesidaWAF.list
# wget -O- https://nemesida-security.com/repo/nw/gpg.key | apt-key add -
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 
# apt update && apt upgrade
# apt install apt-transport-https gnupg2 curl
Ubuntu 18.04
# echo "deb [arch=amd64] https://nemesida-security.com/repo/nw/ubuntu bionic 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 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
Information about using Nemesida WAF in a Docker container is available in the corresponding section.
Information about using Nemesida WAF as a Virtual Appliance (virtual disk for KVM/VMware/VirtualBox) and Yandex VM is available in the corresponding section.

Nginx setup

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

DebianUbuntuCentOSFreeBSD 12/13
Add the Nginx repository:

Debian 10
# echo "deb http://nginx.org/packages/debian/ buster nginx" > /etc/apt/sources.list.d/nginx.list
# wget -O- https://nginx.org/packages/keys/nginx_signing.key | apt-key add -
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 

Install Nginx:

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

Ubuntu 18.04
# echo "deb http://nginx.org/packages/ubuntu/ bionic nginx" > /etc/apt/sources.list.d/nginx.list
# wget -O- https://nginx.org/packages/keys/nginx_signing.key | apt-key add -
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
Connect 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:

# portsnap fetch extract

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

The dynamic module Nemesida WAF is available for:

  • Nginx stable from 1.12;
  • Nginx mainline from 1.15;
  • Nginx Plus from R16.

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 10
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 libmaxminddb0 g++ memcached rabbitmq-server
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 libmaxminddb0 g++ memcached rabbitmq-server
# apt install nwaf-dyn-1.22

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

During the installation of the module, the following PIP packages are additionally installed:
wheel python pandas requests psutil sklearn schedule simple crypt fuzzywuzzy levmatch python-Levenshtein unidecode fsspec func_timeout url-normalize netaddr pymemcache logutils openapi-schema-validator strict-rfc3339 rfc3339-validator isodate

Ubuntu 18.04
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 libmaxminddb0 g++ memcached rabbitmq-server openapi-schema-validator strict-rfc3339 rfc3339-validator isodate
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 libmaxminddb0 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 libmaxminddb0 g++ memcached rabbitmq-server
# apt install nwaf-dyn-1.22

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

During the installation of the module, the following PIP packages are additionally installed:
wheel python pandas requests psutil sklearn schedule simple crypt fuzzywuzzy levmatch python-Levenshtein unidecode fsspec func_timeout url-normalize netaddr pymemcache logutils openapi-schema-validator strict-rfc3339 rfc3339-validator isodate

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
Enable direct connection to nemesida-security.com:443.

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 python36 python36-devel python36-setuptools python36-pip systemd openssl libcurl-devel gcc libmaxminddb memcached rabbitmq-server
# yum install nwaf-dyn-1.22

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

During the installation of the module, the following PIP packages are additionally installed:
wheel python pandas requests psutil sklearn schedule simple crypt fuzzywuzzy levmatch python-Levenshtein unidecode fsspec func_timeout url-normalize netaddr pymemcache logutils openapi-schema-validator strict-rfc3339 rfc3339-validator isodate

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 libmaxminddb memcached rabbitmq-server
# dnf install nwaf-dyn-1.22

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

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 libmaxminddb memcached rabbitmq-server
# dnf install nwaf-dyn-1.22

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

During the installation of the module, the following PIP packages are additionally installed:
wheel cython pandas requests psutil sklearn schedule simple-crypt fuzzywuzzy levmatch python-Levenshtein unidecode fsspec func_timeout url-normalize netaddr pymemcache logutils openapi-schema-validator strict-rfc3339 rfc3339-validator isodate

Update package list:

# portsnap fetch extract

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

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

Install the packages:

# pkg install -y wget memcached libmaxminddb dbus gnutls curl gcc lapack Atlas-devel openblas openssl bash
# service dbus start
# pkg install -y python39 py39-setuptools py39-virtualenv py39-pip py39-cython py39-wheel
# pkg install -y rabbitmq rabbitmq-c
# service rabbitmq start
# curl "https://nemesida-security.com/repo/nw/freebsd/12/nwaf-dyn-1.22-5.1-1568.pkg" --output nwaf-dyn-1.22-5.1-1568.pkg
# pkg install -y nwaf-dyn-1.22-5.1-1568.pkg

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

Configuration Nemesida WAF Community Edition
Add the path to the file with the dynamic module Nemesida WAF 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 1022000 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 1022000 is Nginx 1.22.0 installed on the server. The dynamic module package nwaf-dyn-1.22 is designed to work with Nginx version 1.22, and nwaf-dyn-plus-r22 is designed to work with NGINX Plus R22.

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;

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;

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_ip_lm

Configuring request processing for a specific IP address or subnet with fixation in the DBMS, but without actual blocking (passive 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 (passive 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_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_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;

When applying the parameter, the exact match of the path (vhost/path) is taken into account.

For example, with the value: example.com/uploads the BODY zone analysis exception will be applied for requests to example.com/uploads, but for example.com/uploads.php and example.com/uploads/index.php the parameter will not be applied. With the value *, the BODY zone analysis exception 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.service nwaf_update.service
# systemctl status nginx.service nwaf_update.service

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.

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.

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.

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. For 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. For 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 ххх 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 ххх 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 that is based on a regular expression:

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