Nginx is a lightweight, high-performance web server/reverse proxy and e-mail (IMAP/POP3) proxy. It runs on UNIX, GNU/Linux, BSD variants, Mac OS X, Solaris, and Microsoft Windows. According to Netcraft, 13.50% of all domains on the Internet use nginx web server. Nginx is one of a handful of servers written to address the C10K problem. Unlike traditional servers, Nginx doesn’t rely on threads to handle requests. Instead, it uses a much more scalable event-driven (asynchronous) architecture. Nginx powers several high traffic web sites, such as WordPress, Hulu, Github, and SourceForge.

1. Hide details about nginx

By-default the nginx version is shown in the response headers as shown below.

Having such information will facilitate a hacker in an attempt of attacking the web server.

$ curl -I http://35.226.204.122/
HTTP/1.1 200 OK
Server: nginx/1.14.0 (Ubuntu)
Date: Wed, 06 Jun 2018 14:35:24 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Wed, 06 Jun 2018 14:34:09 GMT
Connection: keep-alive
ETag: "5b17f0e1-264"
Accept-Ranges: bytes

Disable the information leakage by uncommenting the line below in http section in the main nginx config file /etc/nginx/nginx.conf

http {

 

server_tokens off;

 

Save the file and reload nginx

$ sudo systemctl reload nginx

2. Enable X-XSS protection

X-XSS protects the web server against cross-site scripting attacks. Add the line below in http section in main nginx config file /etc/nginx/nginx.conf

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

As shown below:

http {
 server_tokens off;
 add_header X-XSS-Protection "1; mode=block";

Save the file and reload nginx service

3. Disable Undesirable HTTP methods
The desirable HTTP methods include POST, HEAD, GET while the undesirable ones are DELETE or TRACE. These are quite risky as they give provision of stealing cookie information through cross-site tacking attacks.

To disable this add the line below in server section in nginx config file /etc/nginx/sites-available/default

 if ($request_method !~ ^(GET|HEAD|POST)$ )
 {
 return 405;
 }

Add the lines as shown below:

server {
 listen 80 default_server;
 listen [::]:80 default_server;
 # SSL configuration
 #
 # listen 443 ssl default_server;
 # listen [::]:443 ssl default_server;
 #
 # Note: You should disable gzip for SSL traffic.
 # See: https://bugs.debian.org/773332
 #
 # Read up on ssl_ciphers to ensure a secure configuration.
 # See: https://bugs.debian.org/765782
 #
 # Self signed certs generated by the ssl-cert package
 # Don't use them in a production server!
 #
 # include snippets/snakeoil.conf;
 root /var/www/html;
 # Add index.php to the list if you are using PHP
 index index.html index.htm index.nginx-debian.html;
 server_name _;
 location / {
 # First attempt to serve request as file, then
 # as directory, then fall back to displaying a 404.
 try_files $uri $uri/ =404;
 }
 if ($request_method !~ ^(GET|HEAD|POST)$ )
 {
 return 405;
 }

Save the file and reload nginx service

4. Prevent Clickjacking Attacks

Clickjacking attack entails hacker placing hidden link below legitimate button on site and the user unknowingly clicks on the attacker’s link causing malice. In most cases this is done using iframes. Hence in nginx, it’s advisable to insert X-FRAME-OPTIONS “SAMEORIGIN” in the header to limit the browser to load resources only from the web server.

Add the line below in the http section in the main nginx config file /etc/nginx/nginx.conf

add_header X-Frame-Options "SAMEORIGIN";

As shown below:

http {
 server_tokens off;
 add_header X-XSS-Protection "1; mode=block";
 add_header X-Frame-Options "SAMEORIGIN";

Save the file and reload nginx service

5. Always Keep Nginx Up-To-Date
The nginx updates will always ensure that any security vulnerabilities in previous versions or releases have been resolved. Just run the commands below:

$ sudo add-apt-repository ppa:nginx/stable

# Press enter to continue with the repository addition when given the prompt to proceed or not
$ sudo apt update
$ sudo apt install nginx -y

Also: 
– Install SSL Certificate in the nginx web server to encrypt all communication via the internet
– Implement NGINX WAF (NGINX Plus with ModSecurity WAF (Web Application Firewall), which is PCI‑DSS 6.6 compliant and protects web server against DDoS, performs real‑time blacklisting performs audit logs
– Secure Diffie-Hellman for TLS as part of SSL/TLS Optimization
– Disable weak cipher suites to allow only strong ciphers hence reducing vulnerability

6. Hide upstream proxy headers

In the same vein, when nginx is used to proxy requests from an upstream server (such as a PHP-FPM instance), it can be beneficial to hide certain headers sent in the upstream response (for example, the version of PHP running). For example, consider the following response from an nginx server running a PHP application:

[user@server]$ curl -I http://example.com
HTTP/1.1 200 OK
Server: nginx
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding
X-Powered-By: PHP/5.3.3

Disclosing the version of PHP can be undesirable; nginx configurations make this easy to hide with the proxy_hide_header directive:

proxy_hide_header X-Powered-By;

Resending the request to the same server would now have this result:

[user@server]$ curl -I http://example.com
HTTP/1.1 200 OK
Server: nginx
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding

7. Restrict access by IP

Sensitive areas of websites, such as admin control panels, should have strict access controls placed on them. nginx makes it easy to whitelist IP access to certain locations of your website and deny traffic to all other IP addresses:

location /wp-admin {

 # allow access from one IP and an additional IP range,
 # and block everything else
 allow 1.2.3.4;
 allow 192.168.0.0/24;
 deny all;
}

Restrict access by password
Access to certain locations can also be set via password-based credentials, using the same format that Apache’s .htaccess and .htpasswd files use:

location /wp-admin {
 auth_basic "Admin Area";
 auth_basic_user_file /path/to/.htpasswd;
}

Where the contents of .htpasswd looks something like:

user1:password1
user2:password2
user3:password3

Force all connections over TLS

Encrypted communications are only useful when actually in use. If desirable, it is possible to tell browsers to only use TLS connections for your site. This is accomplished with the Strict-Transport-Security header, which can be added in your nginx config like this:

add_header Strict-Transport-Security max-age=15768000;

You can also configure nginx to send a 301 redirect for plaintext HTTP requests to the TLS version of your site:

  server {

 listen 80;

 server_name example.com;

 return 301 https://$host$request_uri;

 } 

 server {

 listen 443 ssl;

 server_name example.com; 

 # the rest of the appropriate server block below...

 }

For modifying php settings

Edit the next file: 
/etc/php/7.2/fpm

for example, edit the next line: 
disable_functions= phpinfo

save changes and restart

sudo systemctl restart php7.0-fpm

Controlling Buffer Overflow Attacks

Edit nginx.conf and set the buffer size limitations for all clients.

# vi /usr/local/nginx/conf/nginx.conf

Edit and set the buffer size limitations for all clients as follows:

## Start: Size Limits & Buffer Overflows ##
client_body_buffer_size 1K;
client_header_buffer_size 1k;
client_max_body_size 1k;
large_client_header_buffers 2 1k;
## END: Size Limits & Buffer Overflows ##

Where,

client_body_buffer_size 1k – (default is 8k or 16k) The directive specifies the client request body buffer size.
client_header_buffer_size 1k – Directive sets the headerbuffer size for the request header from client. For the overwhelming majority of requests a buffer size of 1K is sufficient. Increase this if you have a custom header or a large cookie sent from the client (e.g., wap client).
client_max_body_size 1k– Directive assigns the maximum accepted body size of client request, indicated by the line Content-Length in the header of request. If size is greater the given one, then the client gets the error “Request Entity Too Large” (413). Increase this when you are getting file uploads via the POST method.
large_client_header_buffers 2 1k – Directive assigns the maximum number and size of buffers for large headers to read from client request. By default the size of one buffer is equal to the size of page, depending on platform this either 4K or 8K, if at the end of working request connection converts to state keep-alive, then these buffers are freed. 2x1k will accept 2kB data URI. This will also help combat bad bots and DoS attacks.
You also need to control timeouts to improve server performance and cut clients. Edit it as follows:

## Start: Timeouts ##
client_body_timeout 10;
client_header_timeout 10;
keepalive_timeout 5 5;
send_timeout 10;
## End: Timeouts ##

client_body_timeout 10; – Directive sets the read timeout for the request body from client. The timeout is set only if a body is not get in one readstep. If after this time the client send nothing, nginx returns error “Request time out” (408). The default is 60.
client_header_timeout 10; – Directive assigns timeout with reading of the title of the request of client. The timeout is set only if a header is not get in one readstep. If after this time the client send nothing, nginx returns error “Request time out” (408).
keepalive_timeout 5 5; – The first parameter assigns the timeout for keep-alive connections with the client. The server will close connections after this time. The optional second parameter assigns the time value in the header Keep-Alive: timeout=time of the response. This header can convince some browsers to close the connection, so that the server does not have to. Without this parameter, nginx does not send a Keep-Alive header (though this is not what makes a connection “keep-alive”).
send_timeout 10; – Directive assigns response timeout to client. Timeout is established not on entire transfer of answer, but only between two operations of reading, if after this time client will take nothing, then nginx is shutting down the connection.

Nginx And PHP Security Tips

PHP is one of the popular server side scripting language. Edit /etc/php.ini as follows:

# Disallow dangerous functions
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source,phpinfo,

## Try to limit resources ##

# Maximum execution time of each script, in seconds
max_execution_time = 30

# Maximum amount of time each script may spend parsing request data
max_input_time = 60

# Maximum amount of memory a script may consume (8MB)
memory_limit = 8M

# Maximum size of POST data that PHP will accept.
post_max_size = 8M

# Whether to allow HTTP file uploads.
file_uploads = Off

# Maximum allowed size for uploaded files.
upload_max_filesize = 2M

# Do not expose PHP error messages to external users
display_errors = Off

# Restrict PHP information leakage
expose_php = Off

# Log all errors
log_errors = On
 

# Minimize allowable PHP post size
post_max_size = 1K

# Ensure PHP redirects appropriately
cgi.force_redirect = 0

# Disallow uploading unless necessary
file_uploads = Off


# Avoid Opening remote files
allow_url_fopen = Off
allow_url_include=Off

Disable content-type sniffing on some browsers

Add the following in your nginx.conf or virtual domain:

add_header X-Content-Type-Options nosniff;