Common Nginx Misconfigurations and Hardening Tips
Security for Everyone
As of March 2021, one in three websites on the internet runs on Nginx, according to a web survey by Netcraft. Nginx web server powers high-performance applications in a responsive, efficient manner and is useful for load balancing, HTTP caching, mail proxying, and reverse proxying. With the ability to handle 40,000 inactive HTTP connections with just 10Mb of memory, it is the go-to choice for high-traffic sites. This post covers the Common Nginx misconfigurations that leave your web server open to attack and include practical hardening tips to improve your cybersecurity posture.
Hardening Tips for Nginx Security Misconfiguration
Disable Nginx server_tokens
Information disclosure is a blessing to attackers; finding out the version of Nginx you are running enables them to choose just the right vulnerability to exploit! As such it is recommended that you configure your Nginx webserver to not display its version in the server header by editing the nginx.conf file as follows:
server_tokens off; |
Hide proxy headers
Disable the signature of the platform you are running on e.g Apache or PHP to prevent information disclosure using:
proxy_hide_header X-Powered-By; |
Configure Nginx to use security headers
Add an X-frame-options header to prevent clickjacking attacks.
add_header X-Frame-Options SAMEORIGIN; |
Enforce the use of TLS
You can instruct browsers to only use TLS connections for your site using the strict-transport-security header as follows:
add_header Strict-Transport-Security max-age=15768000 |
If forcing connections to be over TLS is not desirable for your use case, you can instead listen on 443 (HTTPS) instead of 80(HTTP) on a per-server basis as follows:
server {
# server listening for SSL traffic on port 443
|
Limit the use of unwanted HTTP methods
Disable the HTTP methods you have no intention of using on your web server by adding this condition in the location block of the config file.
location / {
|
Restrict Access by IP or password
Nginx gives you the option of whitelisting IP access to select sections of your website, which you can utilize as follows:
location /admin-only {
|
Additionally, Nginx can also enforce access based on passwords like Apache does with .htaccess and .htpasswd files.
location /admin-only {
|
The password file would look as follows:
user:password
|
Common Nginx Misconfigurations
Passing Uncontrolled Requests to PHP
Most Nginx example configs for PHP advocate for passing every URI ending in .php to the PHP interpreter which could result in arbitrary code execution by third parties on most PHP setups.
location ~* \.php$ {
|
In this example, all requests that the .php file extension will be passed to the FastCGI backend. A default PHP configuration is set so that it attempts to guess the file you want to execute in cases where the full path specified does not lead to a file that exists on the system. Let's say you request for /community/anime/naruto.php, which does not exist while /community/anime/naruto.gif actually does exist; the PHP interpreter will process /community/anime/naruto.gif. If naruto.gif contains embedded PHP code, it will execute.
Countermeasures:
● Set cgi.fix_pathinfo=0 in php.ini which causes the PHP interpreter to try only the literal path given and stop processing if the file does not exist.
● disable the execution of PHP files in directories with user uploads.
location /uploads {
|
● Set Nginx to only pass certain PHP files for execution.
location ~* (file1|file2|file3) \.php$ {
|
Missing Root Location
The root directive is positioning in your configuration matters. One of the Nginx configuration pitfalls that administrators are strongly warned against is putting the root directive inside location blocks. If you add root to every location block individually, then an unmatched location block will lack root, which would cause errors. Conversely, failure to put the root directive in a location block would give access to the root folder of the server block.
server {
|
In the above example, the root folder is /etc/nginx/app meaning that files in this folder are available to us. However there is no location for / i.e location / { } but only for /welcome.jpeg. As such, a request like GET ../nginx.conf would show the content of the config file etc/nginx/nginx.conf
As such, requests to / will take you to the path specified in the root directive which is globally set.
Countermeasures:
● make sure to set the root directive for the server block.
● Set the respective root directives for the location blocks as needed.
Using non-standard document root locations
Deviating from the standard root document locations laid out in the Filesystem Hierarchy Standard might seem like a fun idea sometimes. That is of course until someone requests for a file they should not be able to access and you end up getting compromised.
server {
|
In the above example, a request for /pizza would be passed to PHP because the file is not found. However, a request for /etc/passwd would reveal your etc/passwd file meaning attackers would have your user list and password hashes and if your Nginx workers run as root, how your passwords have been hashed as well.
Countermeasures:
● Stick to the standard places to place your web content like /usr/share/www, /srv/, /var/www
● Set your Nginx workers to run as non-privileged users instead of as root or a user with Sudo privileges as shown below
Use the user directive in the /etc/nginx/nginx.conf config file.
#user nobody; |
Uncomment it and change nobody to the user you created
user fornginx; |
Misconfigured Nginx alias & Merge slashes set to off
The alias directive in Nginx directs which replacement should be used in place of the specified location. A misconfigured alias allows attackers to access files outside the target folder by allowing directory traversal.
location /naruto/ {
|
In this example, when a request to /naruto/smile.jpeg is made, the file /cup/ramen/smile.jpeg will be sent instead. However, when the location does not end with the directory separator /,
location /naruto {
|
a request to /naruto../app/config.py will send the file /cup/app/config.py
The Merge slashes directive, usually on by default, is the mechanism used to compress multiple forward slashes into one such that // or //// becomes /. When the misconfigured Nginx alias is coupled with merge slashes set to off, an attacker is able to traverse the system quickly, and in the case where Nginx is used for reverse proxying an application vulnerable to local file inclusion, the use of multiple slashes in the request is an easy way to exploit it.
Countermeasures:
● Set merge_slashes to on
● Ensure all parent prefixed locations for Nginx alias directives end with a directory separator.
Conclusion
With the five hardening tips mentioned above, your cybersecurity posture should improve considerably. Also, remember to keep your Nginx web server up to date and visit this blog for more exciting cybersecurity stories and helpful tips. Till next time, stop using default passwords!
control security posture