Nginx Hardening for Security Implications
The web server has a crucial role in web-based applications. Since most of us leave it to the default configuration, it can leak sensitive data regarding the web server.
By applying numerous configuration tweaks, we can make NGINX more resilient against malicious attacks. Following are some NGINX hardening tips that you can incorporate to improve security.
- 1. Hide NGINX Version
- 2. Disable Unnecessary HTTP Methods
- 3. Disable Directory Listing
- 4. Click Jacking defense with X-Frame Options
- 5. Basic XSS Protection
- 6. Enable HttpOnly and Secure Flag
- 7. Disable ETag
- 8. Enable HTTP/2 Protocol
- 9. Set Referrer Policy
- 10. Set Permissions Policy
-
11. Enforce HSTS (HTTP Strict Transport Security)
1. Hide NGINX Version
Hiding the NGINX version number can prevent attackers from using known vulnerabilities specific to your NGINX version. Exposing the Nginx version can provide attackers with useful information for targeting known vulnerabilities. To hide the version:
Edit the NGINX configuration file:
- RHEL Based Servers
sudo nano /etc/nginx/nginx.conf
- Debian Based Servers
sudo nano /etc/nginx/sites-available/faveo.conf
Find the http
block and add the following line:
server_tokens off;
Save and exit the file.
ctrl + x
Restart NGINX:
sudo systemctl restart nginx
The server_tokens off;
directive disables the display of the NGINX version in HTTP headers and error pages.
2. Disable Unnecessary HTTP Methods
Limiting HTTP methods helps to prevent attacks that exploit certain HTTP methods.
Edit the NGINX configuration file:
- RHEL Based Servers
sudo nano /etc/nginx/nginx.conf
- Debian Based Servers
sudo nano /etc/nginx/sites-available/faveo.conf
Find the http
block and add the following line:
if ($request_method !~ ^(GET|POST|HEAD)$ ) {
return 444;
}
Save and exit the file.
ctrl + x
Restart NGINX:
sudo systemctl restart nginx
This configuration will return a 444 No Response
status code for requests using HTTP methods other than GET, POST, and HEAD, which helps mitigate risks..
3. Disable Directory Listing
Directory listing should be disabled to prevent exposure of sensitive files and directory contents.
Edit the NGINX configuration file:
- RHEL Based Servers
sudo nano /etc/nginx/nginx.conf
- Debian Based Servers
sudo nano /etc/nginx/sites-available/faveo.conf
Find the http
block and add the following line:
location / {
autoindex off;
}
For Faveo Helpdesk, we can skip this step as we have already enabled it in default configuration file as below:
location / {
try_files $uri $uri/ /index.php?$query_string;
}
Save and exit the file.
ctrl + x
Restart NGINX:
sudo systemctl restart nginx
The autoindex off;
directive disables directory listing.
4. Clickjacking Defense with X-Frame-Options
To prevent your content from being used in a frame, which could be exploited for clickjacking attacks:
Edit the NGINX configuration file:
- RHEL Based Servers
sudo nano /etc/nginx/nginx.conf
- Debian Based Servers
sudo nano /etc/nginx/sites-available/faveo.conf
Find the http
block and add the following line:
add_header X-Frame-Options "SAMEORIGIN";
Save and exit the file.
ctrl + x
Restart NGINX:
sudo systemctl restart nginx
The add_header X-Frame-Options "SAMEORIGIN";
directive ensures that your content can only be framed by pages from the same origin.
5. Basic XSS Protection
Enabling XSS protection in modern browsers helps prevent cross-site scripting attacks.
Edit the NGINX configuration file:
- RHEL Based Servers
sudo nano /etc/nginx/nginx.conf
- Debian Based Servers
sudo nano /etc/nginx/sites-available/faveo.conf
Find the http
block and add the following line:
add_header X-XSS-Protection "1; mode=block";
Save and exit the file.
ctrl + x
Restart NGINX:
sudo systemctl restart nginx
The add_header X-XSS-Protection "1; mode=block";
directive enables the XSS filter built into modern browsers.
6. Enable HttpOnly and Secure Flags for Cookies
Setting HttpOnly and Secure flags for cookies helps protect them from theft via client-side scripts and ensures they are only sent over HTTPS.
Edit the NGINX configuration file:
- RHEL Based Servers
sudo nano /etc/nginx/nginx.conf
- Debian Based Servers
sudo nano /etc/nginx/sites-available/faveo.conf
Find the http
block and add the following line:
http {
...
add_header Set-Cookie "HttpOnly;Secure";
...
}
Save and exit the file.
ctrl + x
Restart NGINX:
sudo systemctl restart nginx
The add_header Set-Cookie "HttpOnly;Secure";
directive ensures that cookies are marked as HttpOnly and Secure.
7. Disable ETag
Disabling ETags helps prevent leaking information about the server. Disabling them can enhance privacy.
Edit the NGINX configuration file:
- RHEL Based Servers
sudo nano /etc/nginx/nginx.conf
- Debian Based Servers
sudo nano /etc/nginx/sites-available/faveo.conf
Find the http
block and add the following line:
server {
...
add_header ETag "";
...
}
Save and exit the file.
ctrl + x
Restart NGINX:
sudo systemctl restart nginx
The add_header ETag "";
directive disables the generation of ETag headers.
8. Enable HTTP/2 Protocol
Enabling HTTP/2 can improve performance and security over HTTP/1.1..
Edit the NGINX configuration file:
- RHEL Based Servers
sudo nano /etc/nginx/nginx.conf
- Debian Based Servers
sudo nano /etc/nginx/sites-available/faveo.conf
Find the http
block and add the following line:
listen 443 ssl http2;
Save and exit the file.
ctrl + x
Restart NGINX:
sudo systemctl restart nginx
The listen 443 ssl http2;
directive enables HTTP/2 for improved performance.
9. Set Referrer Policy
A referrer policy can prevent sensitive information from being leaked in HTTP referrer headers. Setting a strict referrer policy enhances privacy and security.
Edit the NGINX configuration file:
- RHEL Based Servers
sudo nano /etc/nginx/nginx.conf
- Debian Based Servers
sudo nano /etc/nginx/sites-available/faveo.conf
Find the http
block and add the following line:
add_header Referrer-Policy "strict-origin";
Save and exit the file.
ctrl + x
Restart NGINX:
sudo systemctl restart nginx
The add_header Referrer-Policy "strict-origin";
directive sets a referrer policy that restricts referrer information sent with requests.
10. Set Permissions Policy
Implementing a permissions policy can enhance the security of your site by controlling the use of certain features. Permissions policies (formerly known as Feature Policy) control which features and APIs can be used in your web application.
Edit the NGINX configuration file:
- RHEL Based Servers
sudo nano /etc/nginx/nginx.conf
- Debian Based Servers
sudo nano /etc/nginx/sites-available/faveo.conf
Find the http
block and add the following line:
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()";
Save and exit the file.
ctrl + x
Restart NGINX:
sudo systemctl restart nginx
The add_header Permissions-Policy "geolocation=(), microphone=(), camera=()";
directive restricts access to certain features.
11. Enforce HSTS-HTTP Strict Transport Security
Enforcing HSTS ensures that browsers only connect to your server over HTTPS.
Edit the NGINX configuration file:
- RHEL Based Servers
sudo nano /etc/nginx/nginx.conf
- Debian Based Servers
sudo nano /etc/nginx/sites-available/faveo.conf
Find the http
block and add the following line:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
Save and exit the file.
ctrl + x
Restart NGINX:
sudo systemctl restart nginx
The add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
directive enforces HSTS for one year and includes all subdomains.
Nginx Virtual Host Configuration for Security Hardening
Here is the combined configuration for Debian-based systems, summarized from all 11 points, to be placed in the virtual host configuration files. Here we are directly making changing in a single virtual host file for a particular website.
Enabling and Applying Configuration:
Edit the NGINX configuration file:
sudo nano /etc/nginx/sites-available/faveo.conf
Edit or create the site-specific configuration file:
server {
root /var/www/faveo/public;
index index.php index.html index.htm;
server_name helpdesk.example.com;
client_max_body_size 100M;
location / {
try_files $uri $uri/ /index.php?$query_string;
#1. Hide NGINX Version
server_tokens off;
#2. Disable Unnecessary HTTP Methods
if ($request_method !~ ^(GET|POST|HEAD)$ ) {
return 444;
}
# Security Headers
#4. Clickjacking Defense with X-Frame-Options
add_header X-Frame-Options "SAMEORIGIN";
#5. Basic XSS Protection
add_header X-XSS-Protection "1; mode=block";
#6. Enable HttpOnly and Secure Flags for Cookies
add_header Set-Cookie "HttpOnly;Secure";
#7. Disable ETag
#add_header ETag "";
etag off;
#9. Set Referrer Policy
add_header Referrer-Policy "strict-origin";
#10. Set Permissions Policy
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()";
#11. Enforce HSTS (HTTP Strict Transport Security)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
#8. Enable HTTP/2 Protocol
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl http2; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/helpdesk.example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/helpdesk.example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = helpdesk.example.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
listen [::]:80;
server_name helpdesk.example.com;
return 404; # managed by Certbot
}
Please make sure that the server name/domain is changed at all locations and ssl paths are correct.
Save and exit the file.
ctrl + x
Restart NGINX:
sudo systemctl restart nginx
Nginx Virtual Host Configuration for Security Hardening
Here is the combined configuration for Debian-based systems, summarized from all 11 points, to be placed in the virtual host configuration files. Here we are directly making changing in a single virtual host file for a particular website.
Enabling and Applying Configuration:
Edit the NGINX configuration file:
sudo nano /etc/nginx/nginx.conf
Edit or create the site-specific configuration file:
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
#Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
#6. Enable HttpOnly and Secure Flags for Cookies
add_header Set-Cookie "HttpOnly;Secure";
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf;
server {
server_name helpdesk.example.com;
root /var/www/faveo/public/;
index index.php index.html index.htm;
#1. Hide NGINX Version
server_tokens off; # Disable server tokens for security
#2. Disable Unnecessary HTTP Methods
if ($request_method !~ ^(GET|POST|HEAD)$ ) {
return 444;
}
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
# This is for user friendly URL
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
#3. Disable Directory listing
autoindex off;
}
# Security Headers
#4. Clickjacking Defense with X-Frame-Options
add_header X-Frame-Options "SAMEORIGIN";
#5. Basic XSS Protection
add_header X-XSS-Protection "1; mode=block";
#7. Disable ETag
#add_header ETag "";
etag off;
#9. Set Referrer Policy
add_header Referrer-Policy "strict-origin";
#10. Set Permissions Policy
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()";
#11. Enforce HSTS (HTTP Strict Transport Security)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
location ~* \.html$ {
expires -1;
}
location ~* \.(css|gif|jpe?g|png)$ {
expires 1M;
add_header Pragma public;
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
}
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
#8. Enable HTTP/2 Protocol
listen 443 ssl http2; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/helpdesk.example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/helpdesk.example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
gzip on;
gzip_http_version 1.1;
gzip_vary on;
gzip_comp_level 6;
gzip_proxied any;
gzip_types application/atom+xml
application/javascript
application/json
application/vnd.ms-fontobject
application/x-font-ttf
application/x-web-app-manifest+json
application/xhtml+xml
application/xml
font/opentype
image/svg+xml
image/x-icon
text/css
text/plain
text/xml;
gzip_buffers 16 8k;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
server {
if ($host = helpdesk.example.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
server_name helpdesk.example.com;
listen 80;
return 404; # managed by Certbot
}}
Please make sure that the server name/domain is changed at all locations and ssl paths are correct.
Save and exit the file.
ctrl + x
Restart NGINX:
sudo systemctl restart nginx