Nginx Security Hardening and Rules

So since i searched the Nginx Forum i can’t find anyone who has posted a
topic for Nginx security rules or examples so i will be the first to
share
my examples regardless of how bad of a idea some people may think that
is.

So the first security addition is to block direct IP access to my server
connecting via IP instead of a assigned domain name will result in a
error
or denied request.

server {
listen 80;
listen [::]:80;
location / {
#deny all;
return 404;
}

Hide your Nginx version / Information by turning of server tokens and
restrict upload file sizes.

server_tokens off;

File uploads

client_max_body_size 10M;

Another thing is to block access to certain directories or config files
even
file paths or locations that could be resource extensive or contain
sensative data allowing access to only your IP.

location ~
^/(xampp|security|phpmyadmin|licenses|webalizer|server-status|server-info|cpanel|configuration.php|htaccess)
{
#deny all;
#return 404;
allow 192.168.1.5;
}

Deny running scripts inside writable directories unless your own IP.

location ~*
/(images|cache|media|logs|tmp)/.*.(php|pl|py|jsp|asp|sh|cgi)$
{
#return 403;
allow 192.168.1.5;
}

Only allow these request methods GET|HEAD|POST Do not accept DELETE,
SEARCH
and other methods.

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

Apparently itpp2012 told me in another post the zero day exploit was
fixed
but i see no harm in having it in here. (And some people still run
outdated
PHP versions.)

location ~ .php$ {

Zero-day exploit defense.

nginx 0day exploit for nginx + fastcgi PHP

Won’t work properly (404 error) if the file is not stored on this

server,
which is entirely possible with php-fpm/php-fcgi.

Comment the ‘try_files’ line out if you set up php-fpm/php-fcgi on

another
machine. And then cross your fingers that you won’t get hacked.
try_files $uri =404;
fastcgi_split_path_info ^(.+.php)(/.+)$;
}

Password restrict directories you only want yourself or admins to
access.

location ~ /administrator/.*) {
auth_basic “Restricted”;
auth_basic_user_file C:/www/vhosts/passwd;
}

Looking forward to see what other people use and if i can adapt anyone
elses
to my own setup, I run a Joomla enviorment but i know that this can be
helpfull for wordpress users too.

Posted at Nginx Forum:

I also came across the following what will completely drop Nginx server
and
PHP / ASP.NET etc Powered by headers.

http {
more_clear_headers ‘Server’;
more_clear_headers ‘X-Powered-By’;

Posted at Nginx Forum:

hi,

i’d suggest you collect your snippets in the nginx-wiki

and link your collecftion back to Getting Started | NGINX

thus it will be easier to maintain and extend.

cheers,

mex

Posted at Nginx Forum:

Thanks mex i will submit a wiki page how long do they take to get added
or
approved ? Also one of the main reasons i posted it here was just to
have
everyone share what they use and some different and custom stuff.

Posted at Nginx Forum:

Hi c0nw0nk,

ping me offlist if you don’t already have a wiki account and i’ll get
you set up.

sarah

i think it’s a nice idea and surely will participate with some stuff
like securtiy-headers (CSP/X-Frame-Options etc)

single issues/questions mgith still be discussed on-list,
and it should be no problem to post updates here from
time to time.

cheers,

mex

Posted at Nginx Forum:

Paste in google:
Top 20 Nginx WebServer Best Security Practices

Posted at Nginx Forum:

I have come across that same page before the one that is interesting me
right now is based of mex’s comment on Security in header responses.

config to don’t allow the browser to render the page inside an frame

or
iframe

and avoid clickjacking Clickjacking - Wikipedia

if you need to allow [i]frames, you can use SAMEORIGIN or even set an

uri
with ALLOW-FROM uri

X-Frame-Options - HTTP | MDN

add_header X-Frame-Options SAMEORIGIN;

when serving user-supplied content, include a X-Content-Type-Options:

nosniff header along with the Content-Type: header,

to disable content-type sniffing on some browsers.

https://www.owasp.org/index.php/List_of_useful_HTTP_headers

currently suppoorted in IE > 8

http://blogs.msdn.com/b/ie/archive/2008/09/02/ie8-security-part-vi-beta-2-update.aspx

Reducing MIME type security risks (Windows) | Microsoft Learn

‘soon’ on Firefox https://bugzilla.mozilla.org/show_bug.cgi?id=471020

add_header X-Content-Type-Options nosniff;

This header enables the Cross-site scripting (XSS) filter built into

most
recent web browsers.

It’s usually enabled by default anyway, so the role of this header is

to
re-enable the filter for

this particular website if it was disabled by the user.

https://www.owasp.org/index.php/List_of_useful_HTTP_headers

add_header X-XSS-Protection “1; mode=block”;

with Content Security Policy (CSP) enabled(and a browser that supports

it(Can I use... Support tables for HTML5, CSS3, etc),

you can tell the browser that it can only download content from the

domains you explicitly allow

https://www.owasp.org/index.php/Content_Security_Policy

I need to change our application code so we can increase security by

disabling ‘unsafe-inline’ ‘unsafe-eval’

directives for css and js(if you have inline css or js, you will need

to
keep it too).

more:

add_header Content-Security-Policy “default-src ‘self’; script-src
‘self’
‘unsafe-inline’ ‘unsafe-eval’ https://ssl.google-analytics.com
https://assets.zendesk.com https://connect.facebook.net; img-src ‘self’
https://ssl.google-analytics.com https://s-static.ak.facebook.com
https://assets.zendesk.com; style-src ‘self’ ‘unsafe-inline’
https://fonts.googleapis.com https://assets.zendesk.com; font-src ‘self’
https://themes.googleusercontent.com; frame-src
https://assets.zendesk.com
https://www.facebook.com https://s-static.ak.facebook.com
https://tautt.zendesk.com; object-src ‘none’”;

Posted at Nginx Forum:

Yeah sorry about that Maxim i don’t actualy use the allow ip feature i
accidently hashed out the #deny all; and this forum does not let us edit
our
posts.

Other than that the following that you posted.

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

For nginx itself this is not needed. Something like this may be
useful if you are protecting your backends. See also limit_except
which can be used on a per-location level:

limit_except GET POST {
deny all;
}

Did you intentionaly miss Head ?
limit_except GET HEAD POST {
deny all;
}

I dont see the benefit from using one to the other they both do the same
thing.

Posted at Nginx Forum:

I just read on the Wiki why you missed out putting head in the
limit_except
block.

“Allowing the GET method makes the HEAD method also allowed.”

Posted at Nginx Forum:

Hello!

On Sat, Oct 18, 2014 at 10:51:20PM -0400, c0nw0nk wrote:

listen [::]:80;
location / {
#deny all;
return 404;
}

This is mostly matchies the server{} block suggested here:

http://nginx.org/en/docs/http/request_processing.html#how_to_prevent_undefined_server_names

It may also be a good idea to configure a default server to return
error, to prevent processing of requests with names not explicitly
specified in the configuration:

server {
    listen 80 default_server;
    return 404;
}

Hide your Nginx version / Information by turning of server tokens and
restrict upload file sizes.

server_tokens off;

I always wonder why people think that hiding versions improves
security.

File uploads

client_max_body_size 10M;

This will increase allowed upload size from 1m to 10m, as
client_max_body_size defaults to 1m. See
Module ngx_http_core_module.

}
This snippet has the “allow” directive, but no “deny” ones. That
is, it will not block anything. See here for docs:

http://nginx.org/en/docs/http/ngx_http_access_module.html

It’s alwo important to note that it will also prevent execution of
other handlers if configured in other locations (e.g.,
“/configuration.php” will be downloaded, if any, not passed to php
via fastcgi). In general, you can’t just thow such a location
into your configuration - it will cause more harm than good.

Deny running scripts inside writable directories unless your own IP.

location ~* /(images|cache|media|logs|tmp)/.*.(php|pl|py|jsp|asp|sh|cgi)$
{
#return 403;
allow 192.168.1.5;
}

See above about allow/deny.

Only allow these request methods GET|HEAD|POST Do not accept DELETE, SEARCH
and other methods.

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

For nginx itself this is not needed. Something like this may be
useful if you are protecting your backends. See also limit_except
which can be used on a per-location level:

limit_except GET POST {
    deny all;
}

http://nginx.org/r/limit_except

machine. And then cross your fingers that you won’t get hacked.
try_files $uri =404;
fastcgi_split_path_info ^(.+.php)(/.+)$;
}

That’s more about php-side misconfiguration, cgi.fix_pathinfo
should be set to 0 in php.ini.

There are something about this here on wiki:

Password restrict directories you only want yourself or admins to access.

location ~ /administrator/.*) {
auth_basic “Restricted”;
auth_basic_user_file C:/www/vhosts/passwd;
}

That’s very bad snippet. You really shouldn’t use regular
expressions instead of prefix locations. And, if there are
locations given by regular expressions, it is important to make
sure the location will have precedence. So it should be:

location ^~ /administrator/ {
    auth_basic "Restricted";
    auth_basic_user_file /path/to/file;

    ... additional configs as needed, e.g., "location ~ \.php$"
}

See some tips about location matching here in the docs:

http://nginx.org/r/location


Maxim D.
http://nginx.org/

Hello!

On Mon, Oct 20, 2014 at 09:37:51AM -0400, c0nw0nk wrote:

Yeah sorry about that Maxim i don’t actualy use the allow ip feature i
accidently hashed out the #deny all; and this forum does not let us edit our
posts.

This is because it’s not a forum, it’s a mailing list.

limit_except GET POST {
deny all;
}

Did you intentionaly miss Head ?
limit_except GET HEAD POST {
deny all;
}

Yes, see Module ngx_http_core_module. HEAD is automatically
included if you specify GET.

I dont see the benefit from using one to the other they both do the same
thing.

The limit_except is expected to be slightly more efficient as
it’ll use already parsed request method id instead of a regular
expression.


Maxim D.
http://nginx.org/

for scanners/indexes of public services your might search for “shodan”

for the valid use of security trhough obscurity:

"My thoughts on this are that obscuring information is helpful to
security
in many cases as it can force an attacker to generate more “noise” which
can
be detected.

Where obscurity is a “bad thing” can be where the defender is relying on
that obscurity as a critical control, and without that obscurity, the
control fails.

So in addition to the one you gave above. An effective use of obscurity
could be removing software name and version information from Internet
facing
services."

src: Rоry McCune /

Posted at Nginx Forum:

On 20/10/2014 07:46, Maxim D. wrote:

I always wonder why people think that hiding versions improves
security.

Security through obscurity - Wikipedia

Usually this is done as a preventive measure against 0days if you’re not
around to fix stuff for instance. automated scanners will scan for a
certain version. If it’s not available, you have a time buffer when you
can patch your stuff, without popping on automated scanners.

Hello!

On Mon, Oct 20, 2014 at 07:24:27PM +0200, Stefanita Rares Dumitrescu
wrote:

version. If it’s not available, you have a time buffer when you can patch
your stuff, without popping on automated scanners.

Assuming that you’ll have a time buffer is a catch. You won’t.
And the worst thing is that your own automated scanners won’t be
able to notify you about known problems if there are any.


Maxim D.
http://nginx.org/

I hate to bring bugs into this topic but seems possible that this is
something Windows related.

But auth_basic is not working.

I have not tested on a official NGINX build i am using itpp2012’s builds
what could be why it is not working but this is my config.

location ~ ^/(administrator) {
auth_basic “Restricted Area”;
auth_basic_user_file C:/server/.htpasswd;
}

And the output result is this.

2014/10/21 14:09:19 [error] 5208#6132: *1 user “admin”: password
mismatch,
client: ::1, server: localhost, request: “GET /administrator/ HTTP/1.1”,
host: “localhost”
2014/10/21 14:09:20 [error] 5208#6132: *1 user “admin”: password
mismatch,
client: ::1, server: localhost, request: “GET /administrator/ HTTP/1.1”,
host: “localhost”
2014/10/21 14:09:21 [error] 5208#6132: *1 user “admin”: password
mismatch,
client: ::1, server: localhost, request: “GET /administrator/ HTTP/1.1”,
host: “localhost”

Also i use the following to generate the htpassword file :
http://www.tools.dynamicdrive.com/password/

And regardless of why i set the password to it does not authorise me
access
the username i always set as admin

this is the current htaccess :
admin:Wjki8C1VIunc2

So that would be
Username : admin
Pass : lol123

But everylogin results in a password mismatch ?

Posted at Nginx Forum:

c0nw0nk Wrote:

I hate to bring bugs into this topic but seems possible that this is
something Windows related.

But auth_basic is not working.
[…]
admin:Wjki8C1VIunc2

So that would be
Username : admin
Pass : lol123

But everylogin results in a password mismatch ?

You need htpasswd from Apache.

htpasswd.exe -nb admin lol123
Automatically using MD5 format on Windows.
admin:$apr1$Yv…$UNeVa4BMqWMQEEhasQ2Gs0

Posted at Nginx Forum:

I use a subdomain for uploads and i am curious if anyone knows the best
way
to only allow access to only the upload url and block / deny everything
else.

location / {
deny all;
}
location ~ .php$ {
deny all;
if ( $args ~
‘option=com_hwdmediashare&task=addmedia.upload([a-zA-Z0-9-_=&])’ ) {
fastcgi_pass web_rack;
}
}

Is this the best way ?

Posted at Nginx Forum:

Thanks itpp2012 i downloaded the htpassword from the apachelounge.com
builds
:slight_smile: works great now.

Posted at Nginx Forum: