Blog / APPS

Consejos para mantener un servidor Nginx seguro en un entorno de producción

Mantener un servidor Nginx en producción puede ser una tarea complicada si no se tienen claras las opciones de configuración. En esta guía encontrarás consejos valiosos para mantener la seguridad.

 · 13 min de lectura

Nginx es uno de los servidores web más populares de código abierto. Está centrado en el rendimiento y es ampliamente usado por todo tipo de empresas en internet. Es muy habitual encontrar Nginx como proxy inverso, balanceador de carga http, etc.

El ingeniero de software ruso, Igor Sysoev, creador de Nginx, comenzó su desarrollo en 2002 y lo lanzó oficialmente en Octubre de 2014 con la intención de solucionar el problema C10k, siglas que se refieren al problema de gestionar diez mil conexiones simultáneas al mismo tiempo.

Nginx tiene una arquitectura controlada por eventos de tipo asíncrona, lo que le permite ser unos de los servidores con más rendimiento y escalabilidad de los disponibles hoy en día. Se estima que en la actualidad hay unas 400 millones de páginas web corriendo sobre este servidor web.

Instalación de Nginx

La instalación de Nginx se realiza mediante un gestor de paquetes ya que suele venir instalado por defecto en la gran mayoría de repositorios. Es extremadamente sencilla.

Desde la terminal, ejecuta los siguientes comandos para instalar Nginx con un usuario no-root con privilegios sudo configurados:

sudo apt-get update
sudo apt-get install nginx

Tras aceptar el proceso, se instalará Nginx y las dependencias necesarias en tu servidor.

Directorios y comandos básicos

Con el servidor Nginx instalado, encontrarás una serie de archivos y directorios desde donde se pueden realizar cambios en su configuración. Los más importantes son los siguientes:

/etc/nginx/

El directorio /etc/nginx/ es el directorio raíz donde puedes encontrar la configuración por defecto de Nginx. Estos archivos de configuración son los que indican al servidor cómo debe comportarse.

/etc/nginx/nginx.conf

Este es el fichero de texto que contiene la configuración global por defecto del servicio Nginx. Este archivo de configuración contiene los ajustes para los procesos de trabajo, registro, carga de módulos adicionales y referencias a otros archivos de configuración.

/etc/nginx/sites-available/ 
/etc/nginx/sites-enabled/

Ambos directorios contienen la configuración de los sitios web que se sirven desde Nginx.

/var/log/nginx/

Este es el directorio por defecto donde Nginx guarda la información de registro o log. Dentro se encuentran los archivos access.log y error.log. El primero contiene una entrada por cada petición que el servicio Nginx procesa. El segundo los eventos y errores que puedan producirse.

Comandos básicos

El servicio Nginx se gestiona enviando comandos desde el terminal. Los principales son los siguientes:

nginx -h

nginx -h muestra el menú de ayuda en la pantalla de la terminal.

nginx -v

Con nginx -v obtendrás la versión Nginx instalada en tu sistema.

nginx -V

Este comando también muestra la versión instalada, pero a diferencia del anterior, también informa sobre los módulos y algunos argumentos de configuración.

nginx -t

Realiza un test para comprobar si la configuración del servicio es correcta y nos informe de los posibles errores y advertencias. Este comando es muy útil si tienes que modificar la configuración o añadir nuevos archivos y módulos.

nginx -T

Realiza un test a la configuración de Nginx y muestra en pantalla la validación. Se suele utilizar con frecuencia en las intervenciones de soporte técnico.

nginx -s signal

El parámetro -s envía una señal al proceso maestro NGINX. Puede enviar señales como stop, quit, reload y volver a open. La señal de parada interrumpe el proceso NGINX inmediatamente. La señal de salida detiene el proceso de NGINX después de terminar de procesar las solicitudes. La señal de recarga recarga la configuración. La señal de reapertura indica a NGINX que reabra los archivos de registro.

Consejos para mantener Nginx seguro en Producción

Si vas a usar Nginx para servir y alojar aplicaciones web, debes tener en cuenta la seguridad. Sobre todo si esas aplicaciones o páginas web van a ser accesibles desde internet. Seguir estos consejos te ayudarán a mantener tu servidor Nginx seguro en un entorno de producción empresarial.

1 – Desactiva los módulos que no utilices

Cuando tu instalas Nginx se incluyen automáticamente muchos módulos en la instalación. Para desactivar algunos de estos módulos, debes compilar Nginx. Te recomendamos que desactives aquéllos módulos que no utilices para minimizar los riesgos de ataques y explotación.

Para desactivar módulos, usa la opción de configuración durante el proceso de instalación. En el siguiente ejemplo verás como se desactiva el módulo de autoindex, que genera automáticamente listados de directorios.

./configure --without-http_autoindex_module
make
make install

2 – Actualiza Nginx con frecuencia

Comenzamos por lo más sencillo que además es uno de los puntos más importantes. El código de Nginx es bastante seguro y estable, pero de vez en cuando, pueden aparecer vulnerabilidades y otros problemas de seguridad relacionados. Cuando esto ocurre, los desarrolladores de Nginx suelen lanzar actualizaciones de seguridad y parches.

Mantener tu instalación lo más actualizada posible te ayudará a mitigar los problemas de seguridad derivados de estas vulnerabilidades. Este mismo consejo se podría aplicar también al sistema operativo que estes utilizando como base de tu servidor web. Ya sea Ubuntu, Debian, CentOS, macOS o cualquier otro.

Si la compatibilidad de tu servicios y aplicaciones te lo permite, actualiza y aplica los parches de seguridad lo antes posible. En Ubuntu server puedes usar este comando para actualizar:

sudo apt-get update
sudo apt upgrade -y

3 – Oculta la versión de Nginx que tienes instalada

Los hackers pueden buscar que versión tienes instalada para atacar las vulnerabilidades o exploit concretos de esa versión. Esconder la versión de Nginx puede hacerles un poco más complicado hackear tu sistema. Para deshabilitar que Nginx muestre la versión instalada en todas las páginas autogeneradas de error, añade esta línea al archivo de configuración nginx.conf:

server_tokens off

Después de editar el archivo de configuración nginx.conf, debes reiniciar o recargar la configuración con alguno de estos comandos:

sudo service nginx reload
sudo service nginx restart

4 – Desactiva los métodos HTTP que no utilices

Para minimizar los riesgos, debes permitir únicamente las peticiones HTTP que normalmente utilices en tus aplicaciones y servicios web. Por lo general, las peticiones GET, HEAD y POST son las más frecuentes. Puedes bloquear el resto en la mayoría de las páginas web. Para ello, añade las siguientes líneas al archivo de configuración, dentro del bloque servidor:

## acepta los siguientes métodos ##
if ($request_method !~ ^(GET|HEAD|POST)$ ) {
return 444;
}
## Bloquea DELETE, SEARCH y otros métodos ##

5 – Ajusta los privilegios con las opciones de Mount

Ajustar los privilegios al mínimo para que Nginx funcione correctamente es una buena práctica para evitar problemas de seguridad. Puedes crear una partición separada para servir los archivos de tu página web. Por ejemplo, crea una partición llamada /dev/sda4 y monta esa partición en /nginx con los permisos noexec, nodev y nosetuid.

LABEL=/nginx   /nginx    ext4     defaults,nosuid,noexec,nodev   1   2

6 – Activa SELinux

SELinux (Security-Enhanced Linux) es una arquitectura de seguridad para los sistemas Linux desarrollada originalmente por la Agencia de Seguridad Nacional de Estados Unidos. Linux con Seguridad Mejorada (SELinux) permite a los administradores controlar todos los procesos, las aplicaciones y los archivos dentro del sistema operativo y bloqueando aquellos procesos que no se consideren necesarios.

Este estricto control sobre los permisos hará que tu servidor Nginx sea mucho más seguro. Ejecuta getsebool -a como se muestra a continuación:

getsebool -a | less
getsebool -a | grep off
getsebool -a | grep on

Para asegurar tu sistema, mira la configuración que está configurada en "on" y cambiala a "off". Después configure los valores booleanos SELinux correctos para mantener la funcionalidad y la protección.

7 – Instala un certificado SSL/TLS

El protocolo HTTP transfiere la información entre el cliente y el servidor en texto plano. Un importante paso para mantener la seguridad en tus páginas web y aplicaciones, es instalar un certificado SSL/TLS para encriptar las transferencias de información.

Existen múltiples formas de instalar un certificado SSL, desde servicios de pago a gratuitos como Let’s Encrypt. A continuación encontrarás el proceso de instalación de un certificado de Let’s Encrypt en una distribución de Linux de tipo Ubuntu:

El primer paso es instalar Certbot y su módulo de Nginx con el gestor de paquetes apt:

sudo apt install certbot python3-certbot-nginx

Si ya tienes configurados tus nombres de dominio en el directorio /etc/nginx/sites-available/midominio.com, puedes ejectuar el siguiente comando para instalar un certifcado SSL en tu servidor:

sudo certbot --nginx -d midominio.com -d www.midominio.com

La primera vez que ejecutes Certbot, te solicitará una dirección de correo electrónico así como la aceptación de sus términos y condiciones. Si la comprobación de las DNS del dominio es correcta, certbot te preguntará si quieres redireccionar todo el tráfico http a https:

Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel):

Selecciona la opción 2 y pulsa intro si tu aplicación web te lo permite.

Si todo es correcto, verás una confirmación similar a ésta:

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/midominio.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/midominio.com/privkey.pem
   Your cert will expire on 2020-08-18. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot again
   with the "certonly" option. To non-interactively renew *all* of
   your certificates, run "certbot renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

A partir de este paso, puedes comprobar si tu página web carga usando el protocolo https.

Los certificados de Let’s Encrypt tienen una validez de 90 días. Con la instalación de Certbot en tu sistema, se incluye un temporizador systemd que se ejecuta dos veces al día y renueva automáticamente los certificados. Puedes comprobar el temporizador utilizando el comando systemctl:

sudo systemctl status certbot.timer

También puedes comprobar el proceso de renovación realizando una simulación con certbot:

sudo certbot renew --dry-run

8 – Usa un mecanismo de intercambio de claves seguro

El propósito del parámetro DH es permitir el intercambio de una clave que se utilizará para cifrar la transcripción de mensajes dentro de una sesión. DH elimina la clave al finalizar la sesión, impidiendo que un atacante pueda recuperar los mensajes intercambiados. Usando OpenSSL, genera un grupo DH único con 2048 bits de este modo:

openssl dhparam -out /etc/ssl/dhparam.pem 2048

Después, añade esta línea a la configuración de Nginx, dentro del bloque servidor:

ssl_dhparam  /etc/ssl/dhparam.pem;

9 – Desactiva los protocolos SSL/TLS antiguos

Existen distintas versiones de los protocolos SSL y TLS que se han ido actualizando con el paso del tiempo. Tener activos en el servidor Nginx versiones obsoletas y sin soporte oficial, es un riesgo innecesario. Estas versiones antiguas pueden ser vulnerables a ataques como Beast (Browser Exploit Against SSL/TLS), Crime (Compression Ratio Info-leak Made Easy) y Poodle (Padding Oracle On Downgraded Legacy Encryption) entre otros.

Por este motivo, es recomendable desactivar las versiones antiguas de SSL/TLS añadiendo la siguiente directiva dentro del bloque servidor en el archivo de configuración de Nginx:

ssl_protocols TLSv1.2 TLSv1.3;

10 – Desactiva los conjuntos de cifrado más débiles

Un conjunto de cifrado (cipher suite) es una combinación de algoritmos que proporcionan cifrado, autenticación e integridad. Para proteger los datos de transferencia, TLS / SSL utiliza uno o más conjuntos de cifrado. Estos se usan durante la negociación SSL / TLS, así como para la transferencia de datos.

Las configuraciones de conjuntos de cifrado antiguas y débiles pueden proporcionar una falsa sensación de seguridad y hacer que su sitio web sea vulnerable a los ataques. Si los usa, el atacante puede interceptar o modificar los datos en tránsito.

Dependiendo de las versiones de Nginx y OpenSSL que tengas instaladas, puedes usar una configuración de los conjuntos de cifrado u otra. Si tienes dudas, puedes usar la herramienta gratuita de Mozilla para generar una configuración.

Dentro del bloque servidor en la configuración de Nginx, añade estas líneas:

ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

11 – Ajusta el Búfer de Control

El búfer es una pequeña ubicación de almacenamiento dentro de la memoria del sistema que aloja temporalmente los datos a medida que comienza la transferencia de una ubicación de memoria a otra. Cuando el tamaño de los datos excede la capacidad del tamaño del búfer, se produce un desbordamiento del búfer. Si se explota, el atacante puede aprovechar esta vulnerabilidad para inyectar código malicioso que pueda comprometer un sistema.

Como práctica de seguridad, se recomienda hacer algunos ajustes en el servidor web para mitigar este tipo de problemas agregando las siguientes líneas de código al archivo nginx.conf:

client_body_buffer_size 1K;
client_header_buffer_size 1k;
client_max_body_size 1k;
large_client_header_buffers 2 1k;

12 – Establece una Política de Seguridad de Contenido (CSP)

La Política de Seguridad de Contenido (CSP) es una capa adicional de protección que ayuda a mitigar ciertos ataques como XSS, de inyección de scripts y de seguimiento de paquetes. La Política de Seguridad de Contenido indica al navegador de internet, que nombres de dominio pueden descargar contenido, incluidos archivos JavaScript y CSS bloqueando el resto.

Puedes agregar una cabecera CSP de este modo:

add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;

13 – Protección XSS

Cross-Site Scripting (XSS) es otro tipo de amenza que permite a los atacantes inyectar y ejecutar código malicioso o script del lado del navegador en tu sitio web.

Puedes añadir la siguiente línea en la configuración de Nginx para evitarlo:

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

14 – Evita los ataques de tipo Click-Jacking

El click jacking es una vulnerabilidad conocida de las aplicaciones web. El atacante utiliza esta técnica para obligar al usuario a hacer clic sin el consentimiento del usuario, lo que lo redirige a un sitio web desconocido. La opción X-Frame en el encabezado de respuesta HTTP se puede usar para indicar si un navegador web debe cargar una página en marco o iframe.

Este problema puede evitarse indicando al navegador que sólo permita cargar iframe si la petición vienen del mismo origen que la aplicación web. Para ello, añade esta línea a la configuración de Nginx:

add_header X-Frame-Options "SAMEORIGIN";

15 – Desactiva el Rastreo de Tipo de Contenido

El rastreo de contenido, también conocido como rastreo de MIME (Extensiones multipropósito de correo de Internet), es la técnica utilizada para inspeccionar el contenido de un flujo de bytes para determinar el formato de archivo de los datos que contiene. Esto también puede causar una vulnerabilidad de seguridad porque un atacante puede aprovechar el rastreo de MIME para enviar un ataque XSS (Cross-Site Scripting).

Por ejemplo, si tu aplicación web permite a los usuarios cargar contenido multimedia como imágenes, un atacante podría cargar un archivo de imagen malicioso que contenga código JavaScript. Cuando un navegador rastrea contenido, se puede engañar para que ejecute ese archivo malicioso. Para evitar ataques de rastreo de contenido, se suele configurar el encabezado de respuesta X-Content-Type-Options en nosniff y esto evita que los navegadores que dependan solo del encabezado Content-Type para rastrear el contenido.

Añade esta linea en la configuración:

add_header X-Content-Type-Options nosniff;

16 – Evita el enlace directo de imágenes

Hotlinking es la técnica de mostrar imágenes en una página web cuando realmente residen en otra. Un usuario crea un enlace a las imágenes de tu sitio y lo muestra en su propio sitio. Esto puede desembocar en un aumento en el ancho de banda de tu servidor.

Para evitar esta posibilidad, puedes añadir el bloqueo de Hotlinking en la configuración de los servidores virtuales de Nginx. Si por ejemplo, las imágenes de tu aplicación web están localizadas en un directorio llamado fotos, puedes añadir la siguiente configuración:

location /fotos/ {
  valid_referers none blocked www.midominio.com midominio.com;
   if ($invalid_referer) {
     return   403;
   }
}

También puedes añadir las extensiones de los archivos gráficos a la configuración de este modo:

valid_referers blocked www.midominio.com midominio.com;
if ($invalid_referer) {
    rewrite ^/fotos/uploads.*\.(gif|jpg|jpeg|png)$ http://www.midominio.com/banned.jpg last
}

17 – Activa HTTP Strict-Transport Security

HTTP Strict-Transport Security es una característica de seguridad que permite a una aplicación web indicar a los navegadores que se comuniquen únicamente con el protocolo HTTPS en lugar de HTTP. Comúnmente es conocida como HSTS.

Para habilitar HSTS, añade los siguientes encabezados a tu archivo de configuración de Nginx:

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

18 – Bloquea las Solicitudes sin Nombre de Dominio

Bloquea todas las peticiones en Nginx que no incluyan un nombre de dominio configurado en los host virtuales. Si un bot realiza escaneos aleatorios del servidor para todos los dominios, bloquéalo. Para bloquearlos, añade estas líneas a la configuración de Nginx:

if ($host !~ ^(midominio.com|www.midominio.com)$ ) {
    return 301 https://midominio.com$request_uri;
}

19 – Bloquea Agentes de Usuario Automáticos

Con el fin de proteger tu servidor Nginx de bots, scripts y otros métodos automatizados de extracción de páginas web, rechaza explícitamente las conexiones de esos agentes de usuario.

Añade estas líneas a la configuración:

if ($http_user_agent ~* LWP::Simple|BBBike|wget) {
    return 403;
}

Observaciones Finales

Con estas medidas, además de los consejos habituales de bloquear los puertos en el firewall que no sean necesarios, estar al día en cuanto a vulnerabilidades y fallos de seguridad, tendrás una instancia de Nginx perfectamente válida para estar en producción. Es evidente que no existe una configuración perfecta ni a prueba de fallos de seguridad, pero estas métodos te ayudarán a tener un sistema seguro con un esfuerzo mínimo.

Recuerda que en Createpps disponemos de servidores privados virtuales donde podrás tener Nginx u otro servicio con seguridad y soporte técnico en castellano e inglés.


Greg Miller

Desarrollador senior especializado en JavaScript con más de 18 años de experiencia profesional. Ha participado en múltiples proyectos y startups.