Using ModSecurity in Nginx project — maintaining protection on WordPress
Tags: nginx, security, webdev, tutorial
Published: 2024-06-25 12:56:42


ModSecurity, one of the world’s most popular web app firewalls (WAF), helps prevent various types of attacks on web applications. Such attacks include SQL injection, cross-site scripting (XSS), and cross-site request forgery (CSRF). ModSecurity is a module for servers such as Apache, Nginx, and IIS.

An alternative to ModSecurity is BitNinja's multi-layered security system for blocking attacks on Linux servers. Its modules include a WAF and an AI scanner. It specializes in protection against SQL injection, XSS, viruses, DoS, and the use of website forms for spam attacks. BitNinja comes in handy if an open-source solution is not suitable for whatever reason. We’ll describe how to use BitNinja in ispmanager in depth in the next article. 

In this article, we’ll look at:
1. disabling ModSecurity in the administrative section of the site
2. secure php.ini settings
3. phpMyAdmin security
4. Roundcube security
5. WordPress security

Example configuration for enabling ModSecurity on a virtual host:

```
server {
    # Enable ModSecurity
    modsecurity on;

    location / {
        # Enabling the ModSecurity rules engine
        modsecurity_rules 'SecRuleEngine On';

        # PHP file processing
        location ~ [^/]\.ph(p\d*|tml)$ {
            try_files /does_not_exist @php;
        }
    }
}

```

In this example, ModSecurity is activated at the server level and the rules engine is enabled for the root directory. PHP file processing is also provided using block location. Ensure that you have a handler configured for `@php` that will process PHP files.
To prevent errors in the administrative section of the site, the administrator's IP should be added to the ModSecurity whitelist. This will help avoid possible errors due to security restrictions.

Here is a rule you can use:

`SecRule REMOTE_ADDR "@ipMatch 1.2.3.4" "phase:1,id:200000001,log,allow"`

Replace `1.2.3.4` with the administrator’s real IP address.

## Disabling ModSecurity in the administrative section of the site


```
location ~* ^/(wp-admin/|wp-login\.php) {
        modsecurity off;
        modsecurity_rules 'SecRuleEngine Off';
        allow 1.2.3.4;
        deny all;
        try_files $uri $uri/ /index.php?$args;
    location ~ \.php$ {
        fastcgi_pass unix:/var/www/php-fpm/1.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param SCRIPT_NAME $fastcgi_script_name;
        include /etc/nginx/fastcgi_params;
    }
    }

```
This Nginx configuration block performs the following actions:

**Disabling ModSecurity.** For paths corresponding to `/wp-admin/` or `wp-login.php`, ModSecurity is disabled. This is done to avoid any conflicts or false positives that may interfere with WordPress administration.

**Access Restriction.** Access to the specified paths is allowed only from IP address `1.2.3.4`. All other requests will be denied. This helps protect the site's administrative interface from unauthorized access.

**PHP file processing.** For files ending in .php, this is configured to pass requests for processing to the FastCGI process that listens on socket `/var/www/php-fpm/1.sock`. This allows PHP scripts from the WordPress administrative section to be processed correctly.

**FastCGI parameters.** The additional parameters `FastCGI`, `SCRIPT_FILENAME` and `SCRIPT_NAME` are set to determine the paths to scripts and process them.

This configuration block helps to ensure the security and smooth operation of the WordPress administrative section on the Nginx server.

I have not described the process of compiling and configuring ModSecurity in detail, as it is a rather broad topic that deserves a separate article. If you have any questions, post them in the comments.

## Secure `php.ini` settings

Secure File `php.ini` settings help improve security for PHP applications, including WordPress websites.

Here are a few important settings:

`display_errors = Off`. Disables the output of PHP errors to the screen. This prevents sensitive information from being leaked.
expose_php = Off. Hides PHP version information in the HTTP response headers.

`allow_url_fopen = Off`. Prohibits files from being opened via URL, reducing the risk of remote attacks.

`allow_url_include = Off`. Prohibits the use of URLs in include and require directives, preventing remote files from being included.

`disable_functions`. Restricts the use of dangerous PHP functions, such as: `eval`, `system`, `shell_exec`, `passthru`, `proc_open`, `popen`, `expect_popen`, `pcntl_alarm`, `pcntl_fork`, `pcntl_waitpid`, `pcntl_wait`, `pcntl_wifexited`, `pcntl_wifstopped`, `pcntl_wifsignaled`, `pcntl_wifcontinued`, `pcntl_wexitstatus`, `pcntl_wtermsig`, `pcntl_wstopsig`, `pcntl_signal`, `pcntl_signal_dispatch`, `pcntl_signal_get_handler`, `pcntl_get_last_error`, `pcntl_strerror`, `pcntl_sigprocmask`, `pcntl_sigwaitinfo`, `pcntl_sigtimedwait`, `exec`, `pcntl_exec`, `pcntl_getpriority`, `pcntl_setpriority`, `pcntl_async_signals`, `pcntl_unshare`.

`open_basedir`. Restricts PHP access to the file system by specifying the directories in which scripts can run.

`session.cookie_httponly = 1`. Makes session cookies inaccessible to client-side scripts, which helps prevent XSS attacks.

`session.cookie_secure = 1`. Ensures that session cookies are only transmitted over secure connections (HTTPS).

These settings minimize the risk of attacks on PHP applications.

Configuring Nginx properly can significantly reduce the security risks associated with web servers and applications. Below, we discuss basic methods for how to strengthen security through Nginx settings and restrict access to prevent attacks.

## phpMyAdmin security

Restrict access to phpMyAdmin: this will prevent exploitation of previously discovered and yet unknown vulnerabilities.

The developers of ispmanager have created a unique URL to protect phpMyAdmin. However, for additional security, it is recommended to configure additional settings.

An example configuration for strengthening protection:

```
cat /etc/nginx/vhosts-includes/phpmyadmin-nginx.conf
location /W4ZP4D9tFnuvZ3g3/phpmyadmin {
allow 1.2.3.4;
deny all;
        alias /usr/share/phpmyadmin;
        index index.php;
}
location ~* ^/W4ZP4D9tFnuvZ3g3/phpmyadmin/(.+\.(jpg|jpeg|gif|css|png|js|ico|html|xml|txt))$ {
        alias /usr/share/phpmyadmin/$1;
        error_page 404 @apache;
}
location ~ ^/W4ZP4D9tFnuvZ3g3/phpmyadmin/(.+\.php)$ {
allow 1.2.3.4;
deny all;
        alias /usr/share/phpmyadmin/$1;
        fastcgi_pass unix:/var/run/php-fpm.www-data.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $request_filename;
        include fastcgi_params;
        error_page 502 = @apache;
        error_page 404 = @apache;
}
location @apache {
        error_log /dev/null crit;
        proxy_pass http://127.0.0.1:8080;
        proxy_redirect http://127.0.0.1:8080 /;
        proxy_set_header Host $host:$server_port;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
}
location ^~ /W4ZP4D9tFnuvZ3g3/phpmyadmin/setup {
        deny all;
}

```
This Nginx configuration is designed to strengthen phpMyAdmin security:

**Restrict access by IP address.** Access to phpMyAdmin is only allowed from IP address `1.2.3.4`. All other requests will be denied. This reduces the risk of unauthorized access.

**Path customization.** phpMyAdmin is accessible through a unique URL path, `/W4ZP4D9tFnuvZ3g3/phpmyadmin`. This makes it more difficult for potential attackers trying to locate and exploit phpMyAdmin.

**Customization page security.** Access to the phpMyAdmin customization page `/W4ZP4D9tFnuvZ3g3/phpmyadmin/setup` is completely blocked, preventing it from being used for attacks.

This configuration is an example of phpMyAdmin protection using Nginx. The configuration can be customized for specific security requirements and server infrastructure.

## Roundcube security

Restrict access to the Roundcube webmail client to minimize the risks from potential vulnerabilities.

Example configuration:

```
cat /etc/nginx/vhosts-includes/roundcube-nginx.conf
location /roundcube {
allow 1.2.3.4;
deny all;
        alias /var/lib/roundcube;
        index index.php;
}
location ~* ^/roundcube/(.+\.(jpg|jpeg|gif|css|png|js|ico|html|xml|txt))$ {
        alias /var/lib/roundcube/$1;
        error_page 404 @apache;
}
location ~ ^/roundcube/(.+\.php)$ {
allow 1.2.3.4;
deny all;
        alias /var/lib/roundcube/$1;
        fastcgi_pass unix:/var/run/php-fpm.www-data.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $request_filename;
        fastcgi_param PHP_VALUE "display_errors=off \n display_startup_errors=off";
        include fastcgi_params;
        error_page 502 = @apache;
        error_page 404 = @apache;
}
location @apache {
        error_log /dev/null crit;
        proxy_pass http://127.0.0.1:8080;
        proxy_redirect http://127.0.0.1:8080 /;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
}

```
Access to Roundcube is only allowed from IP address `1.2.3.4`. All other requests will be denied.

This configuration reduces the risk of unauthorized access to Roundcube by restricting access to the webmail client and preventing common vulnerabilities.

## WordPress security

Here’s a customization that will greatly improve the security of your WordPress site.

Customize these HTTP headers:

**Referrer-Policy.** Sets the policy for sending referrer information. In this case, for cross-domain requests, only the domain will be sent, not the full URL.

**X-Content-Type-Options.** Prevents "MIME sniffing" by forcing the browser to adhere to the specified content type.

**X-XSS-Protection.** Protects against clickjacking by preventing a site from loading in a frame on sites other than those on the same domain.

**Content-Security-Policy (CSP).** Enables a filter built into browsers to protect against cross-site scripting (XSS).

**Strict-Transport-Security.** Limits the sources from which resources can be downloaded and helps prevent various attacks such as XSS and data injection.

Forces the browser to use a secure connection (HTTPS) for all requests for a specified time, here, for a year.

Example settings:

```
server {
…
add_header Referrer-Policy "origin-when-cross-origin" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Xss-Protection "1; mode=block" always;
add_header Content-Security-Policy "default-src 'self' https: data: 'unsafe-inline' 'unsafe-eval';" always;
add_header Strict-Transport-Security "max-age=31536000;";
…
# This file contains the rules for securing a WordPress site
include /etc/nginx/wp-deny.conf;
```

**File contents:**

```
cat /etc/nginx/wp-deny.conf
    location ~ /(robots.txt|ads.txt) {allow all;}
    location ~ /*\.(json|ini|log|md|txt|sql)|LICENSE {
        deny all;
    }
    location ~ /\. {
        deny all;
    }

    location ~* /(?:uploads|wflogs|w3tc-config|files)/.*\.php$ {
        deny all;
        access_log off;
        log_not_found off;
    }

    location ~* /wp-includes/.*.php$ {
	deny all;
	access_log off;
	log_not_found off;
    }

    location ~* /wp-content/.*.php$ {
	deny all;
	access_log off;
	log_not_found off;
    }

    location ~* /themes/.*.php$ {
	deny all;
	access_log off;
	log_not_found off;
    }

    location ~* /plugins/.*.php$ {
	deny all;
	access_log off;
	log_not_found off;
    }
    location = /xmlrpc.php {
	deny all;
	access_log off;
	log_not_found off;
    }
location = /wp-config.php {
	deny all;
	access_log off;
	log_not_found off;
    }
```

These Nginx configuration blocks are designed to improve the security of a WordPress site by restricting access to specific files and directories:

**Access to `robots.txt` and `ads.txt`.** Allows access to all requests to files `robots.txt` and `ads.txt`.

**Restrict access to sensitive files.** Denies access to files with extensions `.json`, `.ini`, `.log`, `.md`, `.txt`, `.sql` as well as file `LICENSE`.

**Denies access to hidden files and directories.** Denies access to all files and directories beginning with a dot. For example, `.htaccess`, `.git`.

**Protect directories from executing PHP files.** Prohibits PHP files from executing in directories `uploads`, `wflogs`, `w3tc-config`, `files`, `wp-includes`, `wp-content`, `themes`, and `plugins`. This prevents malicious `PHP` scripts loaded in these directories from executing.

**Disabling XML-RPC.** Prohibits access to file `xmlrpc.php`, which is used to handle XML-RPC in WordPress. Disabling `XML-RPC` can help prevent certain types of attacks.

**Deny access.** Access to file `wp-config.php` is denied to everyone. This prevents the contents of the file from being read through a web browser, which could leak sensitive information.

These settings will restrict access to potentially dangerous files and directories and protect your WordPress site.

## Key takeaways

We looked at ways to create a layered security system for web applications running on Nginx and minimize the risks of a WordPress site getting hacked.

The 6 most important steps are:

**Enabling ModSecurity.** Configuration example on how to enable ModSecurity at the server level and activate the rules engine for the root directory.

**Disabling ModSecurity in the administrative section of the site.** The article has an example configuration for how to disable ModSecurity in the WordPress administrative section to avoid conflicts and false positives.

**phpMyAdmin security.** The article provides an example configuration that restricts access to PHPMyAdmin by IP address and uses a unique URL for protection.

**RoundCube security.** The article has an example configuration for restricting access to the webmail client Roundcube.

**WordPress security.** The article has an example Nginx configuration and sample HTTP headers to improve site security on WordPress, as well as rules to restrict access to sensitive files and directories.

**Secure Settings php.ini.** The article provides an example of file `php.ini` settings to disable dangerous features and restrict file system access to reduce the risk of attacks on PHP applications.

This is part 3 in a series of articles on How to secure a WordPress site with Linux Debian and ispmanager 6.

**Previous articles:**

- [How to secure a WordPress site with Linux Debian](https://dev.to/ispmanager/how-to-secure-a-wordpress-site-with-linux-debian-29c1)
- [How to secure your WordPress site: audit and monitoring tools](https://dev.to/ispmanager/how-to-secure-a-wordpress-site-auditing-and-monitoring-tools-4ba9)

**In the following articles:**

- Configuring BitNinja
- Configuring the system according to Lynis audit
- Finalizing security settings using whitelists

Want more articles like this? Subscribe to [our newsletter](https://9ce5ba7f.sibforms.com/serve/MUIFADo9TWiTfGbIQS2_6jvU1if3z-K6845WSmXxJOUoLHCEFzrofp-PTPVqQiNhh2Di3xDLMXG-lVfMoRRPkDt64Z_DwSm2yQPIkQVACt--A3R7My3LQnbONtZ7W4W6uaj0ramr9JLDJ3reMAmf7z-lS16D4qAfrlYcD5GUhGNfqfIi0YKkqO5niM7X6TRjUBll72vLzapyY_by)