Nginx Security 101: A Checklist for Keeping Your Web Server Safe and Secure

Overview

Remember, security requires constant attention and improvement. This list may serve as a starting point to harden your web server.

Protect the page with auth_basic

To create a basic authentication page in Nginx, you can use the "auth_basic" and "auth_basic_user_file" directives in the Nginx configuration file. Here are the steps to do so:

Create a file that contains the username and password that you want to use for authentication. The file should be in the following format:

username1:password1
username2:password2
...

You can create this file using the "htpasswd" utility, which is included with Apache.

sudo htpasswd -c /etc/nginx/.htpasswd username1

This command creates the file "/etc/nginx/.htpasswd" and adds the user "username1" to the file. You will be prompted to enter and confirm the password for the user.

Add the "auth_basic" and "auth_basic_user_file" directives to the location block for the page or directory that you want to protect. For example:

location /secure {
    auth_basic "Restricted Access";
    auth_basic_user_file /etc/nginx/.htpasswd;
    ...
}

In this example, the "location" block protects the "/secure" directory with basic authentication. The "auth_basic" directive sets the message that is displayed in the authentication dialog box, and the "auth_basic_user_file" directive specifies the location of the password file that was created in step 1.

Reload the Nginx configuration to apply the changes.

sudo service nginx reload

Now, when a user tries to access the protected page or directory, they will be prompted to enter a username and password. If the credentials match those in the password file, the user will be granted access to the page or directory. If the credentials are incorrect, the user will be prompted to try again.

Limit access to the page from certain IP addresses

To limit access to a page for certain IP addresses in Nginx, you can use the "allow" and "deny" directives. Here are the steps to do so:

Determine the IP addresses that you want to allow or deny access to. You can specify IP addresses individually, or you can use IP address ranges in CIDR notation.

Add a "location" block for the page or directory that you want to restrict access to:

location /restricted {
    ...
}

Use the "allow" and "deny" directives to specify the IP addresses that are allowed or denied access to the page or directory. For example:

location /restricted {
    deny 192.168.1.1;
    allow 192.168.1.0/24;
    allow 10.0.0.0/8;
    deny all;
    ...
}

In this example, access to the "/restricted" directory is denied to the IP address 192.168.1.1, but allowed for the IP address range 192.168.1.0/24 and the IP address range 10.0.0.0/8. The "deny all" directive at the end of the block ensures that all other IP addresses are denied access.

Reload the Nginx configuration to apply the changes.

sudo service nginx reload

Now, when a user tries to access the restricted page or directory, Nginx will check their IP address against the "allow" and "deny" directives in the location block. If their IP address is allowed access, they will be able to view the page or directory. If their IP address is denied access, they will be presented with a "403 Forbidden" error page. Note that this method of access control is not foolproof, as IP addresses can be spoofed or easily changed, but it can be effective as part of a larger access control strategy.

Disable unnecessary modules

During Nginx installation from the source, you can disable unnecessary modules by using --without flag:

./configure --without-mail --without-http_js_module
make
make install

Installation sources can be found here: http://nginx.org/en/download.html

Here is a list of some commonly used modules that can be disabled during compilation:

--without-http_charset_module
--without-http_ssi_module
--without-http_userid_module
--without-http_access_module
--without-http_auth_basic_module
--without-http_autoindex_module
--without-http_geo_module
--without-http_map_module
--without-http_split_clients_module
--without-http_referer_module
--without-http_rewrite_module
--without-http_proxy_module
--without-http_fastcgi_module
--without-http_uwsgi_module
--without-http_scgi_module
--without-http_memcached_module
--without-http_limit_conn_module
--without-http_limit_req_module
--without-http_empty_gif_module
--without-http_browser_module
--without-http_upstream_hash_module
--without-http_upstream_ip_hash_module
--without-http_upstream_least_conn_module
--without-http_upstream_keepalive_module
--without-mail_pop3_module
--without-mail_imap_module
--without-mail_smtp_module

Disable server tokens

With server_tokens directive enabled, Nginx will verbosely display the Nginx version number and the host operating system. It is also visible in all HTTP responses in the Server header. To disable this behavior uncomment or add the following string to the configuration file:

server_tokens off

The "server_tokens" directive can be set to one of three values:

  • "on" (the default) - This value causes Nginx to include the server version information in the "Server" response header field.

  • "off" - This value causes Nginx to exclude the server version information from the "Server" response header field.

  • "build" - This value causes Nginx to include the server version information but only to the extent of the build number.

More information about server_tokens can be found here: http://nginx.org/en/docs/http/ngx_http_core_module.html#server_tokens

Manage buffer size to prevent DoS attacks

To prevent DoS attacks, you can set buffer size limitations for all clients. Use the following directives to specify limits:

The "client_body_buffer_size" directive in Nginx is used to set the size of the buffer used to store client request bodies. When a client sends a request to Nginx that includes a request body (such as a POST or PUT request), Nginx needs to buffer the body until it can be processed. The "client_body_buffer_size" directive sets the maximum size of this buffer. The default value is 8k or 16k but it is recommended to set this as low as 1k: client_body_buffer_size 1k

The "client_header_buffer_size" directive in Nginx is used to set the size of the buffer used to store client request headers. When a client sends a request to Nginx, it includes a set of request headers that provide additional information about the request. These headers can include information such as the user agent, cookies, and custom headers. Nginx needs to buffer these headers until it can process the request. A buffer size of 1k is adequate for most requests.

http {
    client_header_buffer_size 2k;
    ...
}

The "client_max_body_size" directive in Nginx is used to set the maximum size of the client request body that Nginx will accept and buffer in memory.

When a client sends a request to Nginx that includes a request body (such as a POST or PUT request), Nginx needs to buffer the body until it can be processed. The "client_max_body_size" directive sets the maximum size of this buffer.

The default value of "client_max_body_size" is 1 MB. If the size of the request body exceeds the value set in "client_max_body_size", Nginx will return a "413 Request Entity Too Large" error to the client. 1k directive should be sufficient

http {
    client_max_body_size 10m;
    ...
}

The "large_client_header_buffers" directive in Nginx is used to set the maximum size and number of buffers used to store large client request headers.

If a client sends headers that are larger than the default buffer size set by the "client_header_buffer_size" directive, Nginx will return a "400 Bad Request" error. The "large_client_header_buffers" directive allows you to set larger buffer sizes to handle these cases.

The "large_client_header_buffers" directive takes three arguments:

  1. The number of buffers to allocate. The default value is 4.

  2. The size of each buffer. The default value is 8 KB.

  3. The maximum size of the headers to buffer. If the size of the headers exceeds this value, Nginx will return a "414 Request-URI Too Large" error to the client. The default value is 8 KB.

You can set the "large_client_header_buffers" directive in the http, server, or location context of the Nginx configuration file, depending on where you want to apply the setting. For example, to set the maximum size of the headers to 16 KB and allocate 8 buffers of size 16 KB each in the http context, you would add the following line to your Nginx configuration file:

http {
    large_client_header_buffers 8 16k;
    ...
}

It's important to note that setting the buffer sizes too large can consume a lot of memory and impact performance.

Disable Any Unwanted HTTP methods

To disable any unwanted HTTP method in Nginx, you can use the "limit_except" directive. This directive is used to apply access restrictions to HTTP methods other than GET and HEAD.

Here's an example of how to use the "limit_except" directive to disable the HTTP POST method:

location /path {
    limit_except GET HEAD {
        deny all;
    }
    ...
}

In this example, the "limit_except" directive is used to restrict all HTTP methods except GET and HEAD for requests to the "/path" location. The "deny all" directive is used to deny access to any request that uses a restricted HTTP method.

You can also use the "allow" directive to specify a whitelist of IP addresses that are allowed to use a restricted HTTP method:

location /path {
    limit_except GET HEAD {
        allow 192.168.1.0/24;
        deny all;
    }
    ...
}

Use ModSecurity to strengthen your server

ModSecurity is a web application firewall (WAF) that provides protection for web applications against various types of attacks. It is an open-source WAF that is available as a module for the Apache HTTP Server and Nginx web server.

ModSecurity operates as a reverse proxy, meaning that it sits between the client and the server and inspects incoming requests before forwarding them to the server. It uses a set of rules to analyze and block potentially malicious requests. The rules can be customized to match specific web application vulnerabilities and attack patterns.

ModSecurity can detect and prevent a wide range of attacks, including cross-site scripting (XSS), SQL injection, file inclusion, and command injection attacks. It can also block requests from known malicious IP addresses and detect patterns of suspicious behavior.

ModSecurity provides detailed logging of detected events, allowing administrators to investigate and respond to attacks. It also provides real-time monitoring of web traffic and can be integrated with intrusion detection systems (IDS) and security information and event management (SIEM) systems.

More info about ModSecurity can be found here: https://docs.nginx.com/nginx-waf/

Monitor Nginx access and error logs

You can use the following open-source tools to continuously monitor Nginx access and error logs.

  1. Logwatch: Logwatch is a log analysis tool that can be used to monitor Nginx access and error logs. It provides daily reports summarizing the activity on the server, including information on the number of requests, the types of requests, and the IP addresses of clients.

  2. GoAccess: GoAccess is a real-time web log analyzer that can be used to monitor Nginx access logs. It provides interactive reports that can be viewed in a web browser, including information on the number of requests, the most frequently accessed pages, and the IP addresses of clients.

  3. ELK Stack: The ELK Stack is a collection of open-source tools (Elasticsearch, Logstash, and Kibana) that can be used to analyze and visualize log data. Nginx logs can be fed into Logstash, which can parse and enrich the log data before sending it to Elasticsearch for indexing. Kibana can then be used to create interactive dashboards and visualizations based on the indexed data.

  4. AWStats: AWStats is a log file analyzer that can be used to monitor Nginx access logs. It provides reports on the number of requests, the types of requests, and the IP addresses of clients, as well as other useful statistics such as the operating systems and browsers used by clients.

  5. Fluentd: Fluentd is a data collection and processing tool that can be used to stream Nginx access and error logs to other tools or services for analysis. It can be used to send log data to Elasticsearch, Hadoop, or other data stores.

Configure security headers

Nginx allows you to configure a variety of security-related headers to improve the security of your web application. Here are some of the most important security headers that can be configured in Nginx:

X-Content-Type-Options: This header tells the browser not to override the content type specified in the HTTP response headers. This can help prevent certain types of attacks, such as content sniffing attacks.

add_header X-Content-Type-Options "nosniff";

X-XSS-Protection: This header enables the built-in cross-site scripting (XSS) filter in most modern browsers. The filter can help prevent certain types of XSS attacks.

add_header X-XSS-Protection "1; mode=block";

X-Frame-Options: This header tells the browser whether or not to allow the web application to be embedded in a frame or iframe on another site. This can help prevent clickjacking attacks.

add_header X-Frame-Options "SAMEORIGIN";

Content-Security-Policy: This header defines a whitelist of trusted sources of content for various types of resources, including scripts, stylesheets, images, and fonts. This can help prevent certain types of attacks, such as cross-site scripting (XSS) and data injection attacks.

add_header Content-Security-Policy "default-src 'self';";

Strict-Transport-Security: This header tells the browser to only access the web application using HTTPS for a specified period of time. This can help prevent man-in-the-middle (MitM) attacks and cookie hijacking.

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";

These security headers can be added to the Nginx configuration file using the "add_header" directive. You can add them to the http, server, or location context of the configuration file depending on where you want to apply the settings. Note that some headers may not be compatible with older browsers or certain types of web applications, so it's important to test the headers thoroughly before enabling them in production.

Make updates to your Nginx server regularly

Backup your current Nginx configuration and any other important files or data.

Update your package repository to ensure that you have the latest version of Nginx available:

sudo apt update

Upgrade Nginx and its dependencies:

sudo apt upgrade nginx

Verify that the new version of Nginx is installed:

nginx -v

If you have made any customizations to the Nginx configuration file, review the changes made to the default configuration file during the upgrade and apply any necessary changes to your custom configuration file:

diff /etc/nginx/nginx.conf /etc/nginx/nginx.conf.dpkg-dist

Verify that the new version of Nginx is running and serving content:

curl -I localhost

If any errors occur during the upgrade process or if you experience issues after upgrading, you can restore your backup of the previous configuration and data to revert the changes made during the upgrade. It's also a good idea to test the new version of Nginx thoroughly before deploying it to production to ensure that it is compatible with your web application and any other software on your server.

Check your Nginx config with Gixy tool

Gixy is an open-source tool that can be used to scan Nginx configuration files for security vulnerabilities and best practices. It was developed by Yandex, a Russian multinational technology company, and is available under the MIT license.

Gixy is designed to identify common configuration errors and security issues in Nginx, including:
Insecure SSL/TLS configuration

  1. Outdated or vulnerable Nginx versions

  2. Incorrect file permissions

  3. Excessive permissions for Nginx workers

  4. Use of deprecated or insecure Nginx directives

  5. Misconfigured proxy servers

Gixy can be run as a command-line tool or as a Docker container. It scans the Nginx configuration file and provides a report detailing any issues found, including a severity rating and suggested remediation. It can also generate a graphical representation of the configuration file, making it easier to visualize the structure of the configuration and identify potential issues.

References

  1. GUI based tool to create Nginx configurations