Hardening — Asegurando NGINX

Caídas del servidor, problemas se seguridad por la configuración, robo de información confidencial, defacements (modificaciones en el aspecto de la web) o inyección de código malicioso, son algunas de las consecuencias de no disponer de una instalación segura del servidor web.

El hardening en un sistema tiene tres principios básicos que dirigen todo el proceso y que debes tener siempre presente en cualquier configuración que vayas a realizar. Así que, para fortificar un servidor web con NGINX deberemos seguirlos también:

  • Mínimo Punto de Exposición (MPE): Un servidor sólo debe exponerse en lo que sea estrictamente necesario para su rol, es decir, un servidor Web no debe tener cargado el software de impresión y mucho menos ejecutando demonios de servicio de impresión en red. Esta regla ha hecho que las instalaciones de los sistemas operativos hayan dejado de realizarse orientadas a componentes (instalando módulos) y se realicen orientadas a roles (instalando módulos absolutamente necesarios para el cumplimiento de un rol).
  • Mínimo Privilegio Posible (MPP): Todo componente dentro de un sistema debe ejecutarse con los privilegios necesarios para cumplir con su rol y nada más. Un sitio web nunca debe correr como root porque no es necesario para dar servicio y lo único que puede suceder es que un atacante que consiga vulnerar el sitio obtenga esos privilegios de root en el sistema.
  • Defensa en Profundidad (DP): Se deben implementar todas las medidas de seguridad que sean posibles, teniendo en cuenta dos factores:

Primero: Una medida de seguridad no debe anular a otra.

Segundo: Las medidas de protección no pueden anular la utilidad de un sistema. Si las medidas de protección hacen que el sistema deje de dar servicio en tiempo útil entonces no son medidas viables.

Ahora vamos con las configuraciones para mejorar la seguridad de tu NGINX

1- Eliminar información que identifique la versión

a) Sin recompilar

Si el servidor ya está compilado, o no se puede recompilar, se puede quitar la versión que muestra nginx en el archivo de configuración nginx.conf

server_tokens off;

La identificación de la versión también es posible si se observan los mensajes de error del servicio. Para asegurar que no se reporta en ningún momento lo mejor es modificar las siguientes líneas del fichero src/http/ngx_http_special_response.c:

static u_char ngx_http_error_full_tail[ ] =
“<hr><center>” NGINX_VER “</center>” CRLF
“</body>” CRLF
“</html>” CRLF
;
static u_char ngx_http_error_tail[ ] =
“<hr><center>nginx</center>” CRLF
“</body>” CRLF
“</html>” CRLF
;

Por otras que no incluyan la variable NGINX_VER:

static u_char ngx_http_error_full_tail[ ] = CRLF;
static u_char ngx_http_error_tail[ ] = CRLF;

b) Recompilando

Para eliminar la cadena “NGINX” de la cabecera Server antes de compilar el servidor, es necesario modificar el código fuente, en concreto del fichero src/http/ngx_http_header_filter_module.c siguientes líneas:

static char ngx_http_server_string[ ] = “Server: nginx” CRLF;
static char ngx_http_server_full_string[ ] = “Server: “ NGINX_VER CRLF;

Por

static char ngx_http_server_string[ ] = “Server: httpd” CRLF;
static char ngx_http_server_full_string[ ] = “Server: httpd” CRLF;

2- Eliminando módulos que no se utilizan

Una vez modificado el código fuente, se compila deshabilitando todos los módulos que no se usen. La web de nginx facilita una lista completa con su descripción. Especialmente interesante de eliminar es el autoindex. Para deshabilitar se utiliza una línea como la siguiente:

./configure --with-http_ssl_module --without-http_autoindex_module
--without-http_browser_module --without-http_fastcgi_module
--without-http_geo_module --without-http_empty_gif_module
--without-http_map_module  --without-http_proxy_module
--without-http_memcached_module --without-http_ssi_module
--without-http_userid_module  --with-http_ssl_module

Para el caso en que el servidor funcione como Reverse Proxy no se deberá eliminar el módulo http_proxy_module

3- Usuario y grupos de ejecución

Una vez instalado, hay que asegurarse de que no se ejecuta con un usuario con privilegios de administración. En su configuración ha de figurar el usuario y grupo distintos de root.

user              nginx nginx;

4- Páginas de error personalizadas

Se puede especificar en el fichero de configuración, dentro de server {}, cuáles serán las páginas de error personalizadas para cada una de los errores. En este ejemplo se redirige a error.html:

error_page 400 401 402 403 404 405 406 407 408
409 410 411 412 413 414 415 416 417 495 496 497 500 501 502 503 504
505 506 507 /error.html;
location /error.html {
internal;
}

5- Protección Buffer Overflow

Los valores a continuación pueden definirse según el requerimiento de la aplicación. Tomar en cuenta si la aplicación necesita que suban archivos y el tamaño máximo que desea permitir.

## Size Limits & Buffer Overflows
## the size may be configured based on the needs.
client_body_buffer_size  100K;
client_header_buffer_size 1k;
client_max_body_size 100k;
large_client_header_buffers 2 1k;

6- Mitigando Slow HTTP Dos Attack

## Timeouts definition ##
client_body_timeout 10;
client_header_timeout 10;
keepalive_timeout 5 5;
send_timeout 10;
## End ##

7- Remover archivos innecesarios de backup

# find /nginx -name '.?*' -not -name .ht* -or -name '*~' -or -name '*.bak*' -or -name '*.old*'
# find /usr/local/nginx/html/ -name '.?*' -not -name .ht* -or -name '*~' -or -name '*.bak*' -or -name '*.old*'

8- Ignorar todas las cabeceras inválidas

ignore_invalid_headers on;

9- Deshabilitar métodos HTTP

Los métodos HTTP que se pueden utilizar en un servidor web Apache deben estar restringidos para que sólo se usen aquellos que sean estrictamente necesarios. GET, POST y HEAD deberían ser más que suficientes para una web “normal”. Si permites OPTIONS te van a poder examinar todos los métodos permitidos; si permites TRACE te puedes encontrar con alguna situación como la de robar las cookies HTTPOnly.

Si permites el método PUT o DELETE te puedes encontrar algún punto de la web en los que por fallos de los permisos te acaben metiendo una webshell O que aparezcas en una búsqueda por Shodan en un ataque de hacking con buscadores o borrando ficheros.

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

10- Negar ejecución de scripts en directorios

# deny scripts inside writable directories
location ~* /(directorio| directorio | directorio | directorio | tmp)/.*.(php|pl|py|jsp|asp|sh|cgi)$ {
return 403;
error_page 403 /error_page.html;
}

11- Bloquear sparmmers

#bloquear sparmmers
if ( $http_referer ~* (babes|forsale|girl|jewelry|love|nudit|organic|poker|porn|sex|teen) ){
return 403;
}

12- Bloquear Agentes y robots

#Bloquear Agentes y robots
if ($http_user_agent ~* (acunetix|sqlmap|nikto|metasploit|hping3|maltego|nessus|webscarab|sqlsus|sqlninja|aranchni|netsparker|nmap|dirbuster|zenmap|hydra|owasp-zap|w3af|vega|burpsuite|aircrack-ng|whatweb|medusa) ) {
return 403;
}

13- Bloquear algunos robots

## Block some nasty robots
if ($http_user_agent ~ (msnbot|Purebot|Baiduspider|Lipperhey|Mail.Ru|scrapbot) ) {
return 403;
}

14- Bloquear download agent

## Block download agent
if ($http_user_agent ~* LWP::Simple|wget|libwww-perl) {
return 403;
}

15- NGINX como reverse proxy

Es una buena práctica que el servidor NGINX sea capaz de reenviar la dirección IP origen desde donde se realiza la consulta al servidor que esté funcionando como backend.

En el caso de un ataque a un servidor o aplicación que esté detrás de un RP, es conveniente que la dirección IP del ataque, o la dirección IP origen de la solicitud quede registradas en los logs.

Si el servidor reverse proxy (NGINX) no redirige la dirección IP de la solicitud, en el backend solo quedarán registros de la dirección IP del reverse proxy, lo que complicaría el análisis de los logs en caso de un incidente.

Se pueden colocar las siguientes configuraciones en el servidor RP NGINX

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

16- Configuración SSL

#ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';

#Para compatibilidad con IE6 y WINXP los siguientes
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";

#Usar una clave Diffie-Hellman > 2048, se puede generar con el comando
# cd /etc/ssl/certs; openssl dhparam -out dhparams.pem 4096
ssl_dhparam /etc/ssl/certs/dhparam.pem;

#No usar SSLv2 / SSLv3 / TLSv1
ssl_protocols TLSv1.1 TLSv1.2;

#Usar la preferencia del servidor y no la del cliente.
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;

#Otras recomendaciones cabeceras HTTP
ssl_session_timeout 10m;
# X-Frame-Options is to prevent from clickJacking attack
add_header X-Frame-Options SAMEORIGIN;
# disable content-type sniffing on some browsers.
add_header X-Content-Type-Options nosniff;
# This header enables the Cross-site scripting (XSS) filter
add_header X-XSS-Protection "1; mode=block";
# This will enforce HTTP browsing into HTTPS and avoid ssl stripping attack
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";

ssl_session_tickets off;
ssl_stapling on; # Requires nginx >= 1.3.7
ssl_stapling_verify on;
keepalive_timeout 60;

Te dejo un artículo con más información sobre este punto (ver aquí).

17- HTTP secure Header

# X-Frame-Options is to prevent from clickJacking attack
add_header X-Frame-Options SAMEORIGIN;
# disable content-type sniffing on some browsers.
add_header X-Content-Type-Options nosniff;
# This header enables the Cross-site scripting (XSS) filter
add_header X-XSS-Protection “1; mode=block”;
# This will enforce HTTP browsing into HTTPS and avoid ssl stripping attack
add_header Strict-Transport-Security “max-age=31536000; includeSubdomains;”;

Sobre este punto tenemos un artículo donde profundizamos más el tema de las cabeceras de respuesta HTTP (ver aquí)

Para finalizar te recordamos que estas son algunas recomendaciones que el equipo de GuayoyoLabs te propone, pero siempre es conveniente verificar si se adaptan a las necesidades o funcionamiento de nuestros sistemas.

Artículos relacionados:

Asegurando las cabeceras de respuestas HTTP en servidores web Apache y NGINX

Asegurando las cabeceras de respuestas HTTP en servidores web IIS

Hardening — Mejorando configuraciones SSL/TLS