Hardening de Apache y Nginx

El hardening de servidores web es una práctica de seguridad crítica que protege tu infraestructura de ciberataques, violaciones de datos y acceso no autorizado. Tanto Apache como Nginx son servidores web potentes, pero sus configuraciones predeterminadas a menudo priorizan la facilidad de uso sobre la seguridad. Esta guía completa cubre técnicas esenciales de hardening para Apache y Nginx, ayudándote a construir una postura de seguridad robusta que proteja tus aplicaciones, datos y usuarios de amenazas en evolución.

El hardening de servidores implica implementar múltiples capas de controles de seguridad incluyendo ocultar información del servidor, restringir acceso, deshabilitar características innecesarias, implementar protocolos de comunicación seguros y configurar permisos de archivos apropiados. Ya sea que estés ejecutando plataformas de comercio electrónico, sitios web corporativos o servicios de API, el hardening apropiado del servidor web es fundamental para tu estrategia de seguridad general y requisitos de cumplimiento.

Tabla de Contenidos

Prerequisitos

Antes de hardening de tus servidores web, asegúrate de tener:

  • Sistema Operativo: Ubuntu 20.04/22.04, Debian 10/11, CentOS 8/Rocky Linux 8, o similar
  • Servidor Web: Apache 2.4+ o Nginx 1.18+ instalado y en ejecución
  • Acceso root o sudo: Requerido para modificar configuraciones de sistema y servidor
  • Respaldo: Respaldo completo de archivos de configuración actuales
  • Certificado SSL/TLS: Certificado SSL válido para implementación HTTPS
  • Conocimiento básico: Comprensión de HTTP, configuración de servidores web y administración Linux
  • Entorno de pruebas: Recomendado para probar cambios antes de aplicar en producción

Comprendiendo el Hardening de Servidores Web

¿Qué es el Hardening de Servidores Web?

El hardening de servidores web es el proceso de mejorar la seguridad del servidor reduciendo su superficie de ataque, eliminando servicios innecesarios, implementando controles de seguridad y siguiendo mejores prácticas de seguridad. El objetivo es minimizar vulnerabilidades que los atacantes podrían explotar.

Objetivos clave:

  • Minimizar la superficie de ataque deshabilitando características innecesarias
  • Implementar el principio de mínimo privilegio
  • Cifrar datos en tránsito con SSL/TLS fuerte
  • Ocultar información del servidor de los atacantes
  • Implementar controles de acceso y autenticación
  • Monitorear y registrar eventos de seguridad
  • Mantener el software actualizado con parches de seguridad

Vulnerabilidades Comunes de Servidores Web

Divulgación de información: Información de versión del servidor y configuración expuesta SSL/TLS débil: Protocolos obsoletos y suites de cifrado débiles Directory traversal: Acceso no autorizado al sistema de archivos Clickjacking: Embedding malicioso en iframe Cross-Site Scripting (XSS): Inyección de scripts del lado del cliente Ataques DDoS: Ataques de agotamiento de recursos Mala configuración: Configuraciones predeterminadas inseguras Software obsoleto: Vulnerabilidades conocidas en versiones antiguas

Hardening de Apache

Ocultar Versión y SO de Apache

Prevenir divulgación de información ocultando detalles del servidor:

# Edit Apache security configuration
sudo nano /etc/apache2/conf-available/security.conf

Agregar o modificar:

# Hide Apache version
ServerTokens Prod

# Hide server signature
ServerSignature Off

# Disable TRACE HTTP method (prevents XST attacks)
TraceEnable Off

Habilitar configuración y reiniciar:

sudo a2enconf security
sudo systemctl restart apache2

Deshabilitar Módulos Innecesarios

Reducir superficie de ataque deshabilitando módulos no utilizados:

# List enabled modules
apache2ctl -M

# Disable unnecessary modules
sudo a2dismod status          # Server status
sudo a2dismod userdir         # User directories
sudo a2dismod autoindex       # Directory listing
sudo a2dismod cgi             # CGI execution
sudo a2dismod dav             # WebDAV
sudo a2dismod dav_fs          # WebDAV filesystem

# Keep only essential modules:
# - ssl (for HTTPS)
# - rewrite (for URL rewriting)
# - headers (for security headers)
# - expires (for caching)

# Restart Apache
sudo systemctl restart apache2

Permisos y Opciones de Directorio

Configurar permisos estrictos de directorio:

# Edit main configuration or virtual host
sudo nano /etc/apache2/apache2.conf
# Default restrictive policy
<Directory />
    Options None
    AllowOverride None
    Require all denied
</Directory>

# Web root configuration
<Directory /var/www/html>
    # Disable directory listing
    Options -Indexes -Includes -ExecCGI

    # Allow symbolic links (if needed)
    # Options +FollowSymLinks

    # Disable .htaccess if not needed (better performance)
    AllowOverride None

    # Or allow specific overrides only
    # AllowOverride FileInfo AuthConfig

    # Access control
    Require all granted

    # Limit HTTP methods
    <LimitExcept GET POST HEAD>
        Require all denied
    </LimitExcept>
</Directory>

# Protect sensitive files
<FilesMatch "^\.ht">
    Require all denied
</FilesMatch>

# Protect backup and config files
<FilesMatch "\.(bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist)$">
    Require all denied
</FilesMatch>

Limitar Tamaño de Peticiones

Prevenir ataques DoS limitando tamaños de peticiones:

sudo nano /etc/apache2/apache2.conf
# Limit request body size (10MB example)
LimitRequestBody 10485760

# Limit request field size
LimitRequestFieldSize 8190

# Limit number of request fields
LimitRequestFields 100

# Limit request line size
LimitRequestLine 8190

# Timeout configurations
Timeout 60
KeepAliveTimeout 5

Configurar ModSecurity (Web Application Firewall)

Instalar y configurar ModSecurity:

# Install ModSecurity
sudo apt install libapache2-mod-security2 -y

# Enable module
sudo a2enmod security2

# Copy recommended configuration
sudo cp /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf

# Edit configuration
sudo nano /etc/modsecurity/modsecurity.conf
# Enable ModSecurity
SecRuleEngine On

# Set audit log
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
SecAuditLogParts ABIJDEFHZ
SecAuditLogType Serial
SecAuditLog /var/log/apache2/modsec_audit.log

# Request body access
SecRequestBodyAccess On
SecRequestBodyLimit 13107200
SecRequestBodyNoFilesLimit 131072

# Response body access
SecResponseBodyAccess On
SecResponseBodyLimit 524288

Instalar OWASP Core Rule Set:

# Download OWASP CRS
cd /tmp
wget https://github.com/coreruleset/coreruleset/archive/v3.3.4.tar.gz
tar -xvzf v3.3.4.tar.gz
sudo mv coreruleset-3.3.4 /etc/modsecurity/crs
cd /etc/modsecurity/crs
sudo cp crs-setup.conf.example crs-setup.conf

# Load CRS rules
sudo nano /etc/apache2/mods-enabled/security2.conf

Agregar:

IncludeOptional /etc/modsecurity/*.conf
IncludeOptional /etc/modsecurity/crs/crs-setup.conf
IncludeOptional /etc/modsecurity/crs/rules/*.conf
# Restart Apache
sudo systemctl restart apache2

Configuración de Usuario y Grupo

Ejecutar Apache con mínimos privilegios:

# Edit Apache configuration
sudo nano /etc/apache2/envvars
# Use dedicated non-privileged user
export APACHE_RUN_USER=www-data
export APACHE_RUN_GROUP=www-data

Establecer propiedad de archivos apropiada:

# Set ownership of web files
sudo chown -R www-data:www-data /var/www/html

# Set directory permissions (755)
sudo find /var/www/html -type d -exec chmod 755 {} \;

# Set file permissions (644)
sudo find /var/www/html -type f -exec chmod 644 {} \;

Hardening de Nginx

Ocultar Versión de Nginx

Prevenir divulgación de información de versión:

# Edit main Nginx configuration
sudo nano /etc/nginx/nginx.conf
http {
    # Hide Nginx version
    server_tokens off;

    # Additional headers will be configured per server block
}

Deshabilitar Módulos Innecesarios

Nginx es modular; compilar solo módulos necesarios o usar módulos dinámicos:

# Check compiled modules
nginx -V 2>&1 | grep -o with-[a-z_-]*

# For custom builds, recompile without unnecessary modules
# Example: ./configure --without-http_autoindex_module --without-http_ssi_module

Configurar Bloques de Servidor de Forma Segura

Implementar configuración segura de bloques de servidor:

sudo nano /etc/nginx/sites-available/default
server {
    listen 80;
    server_name example.com www.example.com;

    # Redirect to HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com www.example.com;

    root /var/www/html;
    index index.html index.php;

    # Hide Nginx version
    server_tokens off;

    # Security headers (will configure later)
    include /etc/nginx/snippets/security-headers.conf;

    # SSL configuration (will configure later)
    include /etc/nginx/snippets/ssl-params.conf;

    # Disable unwanted HTTP methods
    if ($request_method !~ ^(GET|HEAD|POST)$ ) {
        return 405;
    }

    # Limit request size
    client_max_body_size 10M;
    client_body_buffer_size 128k;

    # Timeouts
    client_body_timeout 10s;
    client_header_timeout 10s;
    keepalive_timeout 5s 5s;
    send_timeout 10s;

    # Disable directory listing
    autoindex off;

    # Protect sensitive files
    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }

    # Protect backup and config files
    location ~* \.(bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist)$ {
        deny all;
    }

    # Main location
    location / {
        try_files $uri $uri/ =404;
    }

    # PHP processing (if needed)
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;

        # Security for PHP
        fastcgi_param PHP_VALUE "open_basedir=/var/www/html:/tmp";
        fastcgi_param PHP_ADMIN_VALUE "disable_functions=exec,passthru,shell_exec,system";
    }

    # Deny access to uploads directory PHP execution
    location ~* /uploads/.*\.php$ {
        deny all;
    }

    # Static files caching
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    # Logs
    access_log /var/log/nginx/example.com-access.log;
    error_log /var/log/nginx/example.com-error.log;
}

Limitación de Tasa

Implementar limitación de tasa para prevenir abuso:

sudo nano /etc/nginx/nginx.conf
http {
    # Define rate limit zones
    limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
    limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
    limit_req_zone $binary_remote_addr zone=api:10m rate=100r/s;

    # Connection limits
    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;

    # In server block:
    server {
        # Apply general rate limit
        limit_req zone=general burst=20 nodelay;
        limit_conn conn_limit 10;

        # Login endpoint with stricter limits
        location = /login {
            limit_req zone=login burst=5 nodelay;
        }

        # API with higher limits
        location /api/ {
            limit_req zone=api burst=50 nodelay;
        }
    }
}

Protección contra Desbordamiento de Buffer

Configurar tamaños de buffer para prevenir ataques de desbordamiento:

http {
    # Buffer size for POST submissions
    client_body_buffer_size 128k;
    client_max_body_size 10m;

    # Buffer size for request headers
    client_header_buffer_size 1k;
    large_client_header_buffers 4 16k;

    # Connection settings
    client_body_timeout 10s;
    client_header_timeout 10s;
    send_timeout 10s;

    # Keep-alive settings
    keepalive_timeout 5s 5s;
    keepalive_requests 100;
}

Configuración de Usuario y Grupo

Ejecutar Nginx con privilegios mínimos:

# Edit main configuration
sudo nano /etc/nginx/nginx.conf
# Run as non-privileged user
user www-data;

# Worker processes (set to auto or number of CPU cores)
worker_processes auto;

# Worker connections
events {
    worker_connections 1024;
}

Establecer permisos de archivo apropiados:

# Set ownership
sudo chown -R www-data:www-data /var/www/html

# Set directory permissions
sudo find /var/www/html -type d -exec chmod 755 {} \;

# Set file permissions
sudo find /var/www/html -type f -exec chmod 644 {} \;

Medidas de Seguridad Comunes

Implementar Fail2Ban

Proteger contra ataques de fuerza bruta:

# Install Fail2Ban
sudo apt install fail2ban -y

# Create local configuration
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5
destemail = [email protected]
sendername = Fail2Ban
action = %(action_mwl)s

# Apache jail
[apache-auth]
enabled = true
port = http,https
logpath = /var/log/apache*/*error.log

[apache-badbots]
enabled = true
port = http,https
logpath = /var/log/apache*/*access.log

[apache-noscript]
enabled = true
port = http,https
logpath = /var/log/apache*/*error.log

# Nginx jail
[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/*error.log

[nginx-limit-req]
enabled = true
port = http,https
logpath = /var/log/nginx/*error.log

[nginx-botsearch]
enabled = true
port = http,https
logpath = /var/log/nginx/*access.log
maxretry = 2
# Restart Fail2Ban
sudo systemctl restart fail2ban

# Check status
sudo fail2ban-client status

Mantener Software Actualizado

Actualizar regularmente el software del servidor web:

# Ubuntu/Debian
sudo apt update
sudo apt upgrade apache2 nginx -y

# CentOS/Rocky Linux
sudo dnf update httpd nginx -y

# Enable automatic security updates
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure -plow unattended-upgrades

Deshabilitar Servicios Innecesarios

Eliminar o deshabilitar servicios no utilizados:

# List running services
systemctl list-units --type=service --state=running

# Disable unnecessary services (examples)
sudo systemctl stop telnet.socket
sudo systemctl disable telnet.socket

# Only run required web server
# If running Nginx, stop Apache and vice versa

Hardening SSL/TLS

Generar Parámetros DH Fuertes

# Generate 4096-bit DH parameters (takes several minutes)
sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096

Configuración SSL de Apache

sudo nano /etc/apache2/mods-available/ssl.conf
<IfModule mod_ssl.c>
    # Enable SSL
    SSLEngine on

    # Modern SSL protocols only
    SSLProtocol -all +TLSv1.2 +TLSv1.3

    # Strong cipher suites
    SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
    SSLHonorCipherOrder off

    # SSL compression (disable to prevent CRIME attack)
    SSLCompression off

    # SSL session cache
    SSLSessionCache shmcb:/var/cache/apache2/ssl_scache(512000)
    SSLSessionCacheTimeout 300

    # Disable SSL session tickets
    SSLSessionTickets off

    # OCSP Stapling
    SSLUseStapling on
    SSLStaplingCache shmcb:/var/cache/apache2/stapling_cache(128000)

    # DH parameters
    SSLOpenSSLConfCmd DHParameters /etc/ssl/certs/dhparam.pem
</IfModule>

Configuración SSL de Nginx

Crear snippet de configuración SSL:

sudo nano /etc/nginx/snippets/ssl-params.conf
# SSL certificates
ssl_certificate /etc/ssl/certs/example.com.crt;
ssl_certificate_key /etc/ssl/private/example.com.key;

# SSL protocols
ssl_protocols TLSv1.2 TLSv1.3;

# SSL ciphers
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers off;

# SSL session cache
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;

# DH parameters
ssl_dhparam /etc/ssl/certs/dhparam.pem;

# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

Control de Acceso

Control de Acceso Basado en IP

Apache:

<Directory /var/www/html/admin>
    <RequireAll>
        Require ip 192.168.1.0/24
        Require ip 10.0.0.100
    </RequireAll>
</Directory>

Nginx:

location /admin {
    allow 192.168.1.0/24;
    allow 10.0.0.100;
    deny all;
}

Autenticación Básica

Apache:

# Create password file
sudo htpasswd -c /etc/apache2/.htpasswd admin

# Configure protection
sudo nano /etc/apache2/sites-available/example.conf
<Directory /var/www/html/admin>
    AuthType Basic
    AuthName "Admin Area"
    AuthUserFile /etc/apache2/.htpasswd
    Require valid-user
</Directory>

Nginx:

# Create password file
sudo htpasswd -c /etc/nginx/.htpasswd admin

# Configure protection
sudo nano /etc/nginx/sites-available/example
location /admin {
    auth_basic "Admin Area";
    auth_basic_user_file /etc/nginx/.htpasswd;
}

Cabeceras de Seguridad

Cabeceras de Seguridad de Apache

sudo nano /etc/apache2/conf-available/security-headers.conf
<IfModule mod_headers.c>
    # HTTP Strict Transport Security
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"

    # Prevent clickjacking
    Header always set X-Frame-Options "SAMEORIGIN"

    # Prevent MIME sniffing
    Header always set X-Content-Type-Options "nosniff"

    # XSS Protection
    Header always set X-XSS-Protection "1; mode=block"

    # Referrer Policy
    Header always set Referrer-Policy "strict-origin-when-cross-origin"

    # Content Security Policy
    Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';"

    # Permissions Policy
    Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"

    # Remove server information
    Header unset Server
    Header unset X-Powered-By
</IfModule>
sudo a2enconf security-headers
sudo systemctl reload apache2

Cabeceras de Seguridad de Nginx

sudo nano /etc/nginx/snippets/security-headers.conf
# HTTP Strict Transport Security
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

# Prevent clickjacking
add_header X-Frame-Options "SAMEORIGIN" always;

# Prevent MIME sniffing
add_header X-Content-Type-Options "nosniff" always;

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

# Referrer Policy
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

# Content Security Policy
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';" always;

# Permissions Policy
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;

Incluir en bloque de servidor:

server {
    include /etc/nginx/snippets/security-headers.conf;
}

Verificación y Pruebas

Verificar Configuración SSL

# Test with SSL Labs
# https://www.ssllabs.com/ssltest/

# Check locally with openssl
openssl s_client -connect example.com:443 -tls1_2

# Check certificates
openssl x509 -in /etc/ssl/certs/example.com.crt -text -noout

Validación de Cabeceras de Seguridad

# Check headers with curl
curl -I https://example.com

# Or use online tools:
# Security Headers: https://securityheaders.com
# Mozilla Observatory: https://observatory.mozilla.org

Escaneo de Vulnerabilidades

# Install Nikto web scanner
sudo apt install nikto -y

# Scan web server
nikto -h https://example.com

# Install and run nmap
sudo apt install nmap -y
nmap -sV -p 80,443 example.com

Solución de Problemas

Errores 403 Forbidden

Causa: Permisos o controles de acceso demasiado restrictivos

Solución:

# Check file permissions
ls -la /var/www/html

# Fix permissions
sudo chown -R www-data:www-data /var/www/html
sudo find /var/www/html -type d -exec chmod 755 {} \;
sudo find /var/www/html -type f -exec chmod 644 {} \;

# Check Apache/Nginx error logs
sudo tail -f /var/log/apache2/error.log
sudo tail -f /var/log/nginx/error.log

Problemas de Certificado SSL

Solución:

# Check certificate validity
openssl x509 -in /etc/ssl/certs/example.com.crt -noout -dates

# Verify certificate chain
openssl verify -CAfile /etc/ssl/certs/chain.pem /etc/ssl/certs/example.com.crt

# Check SSL configuration
apache2ctl configtest
nginx -t

Limitación de Tasa Demasiado Agresiva

Solución:

# Adjust Nginx rate limits
limit_req zone=general burst=50 nodelay;  # Increase burst

# Or increase rate
limit_req_zone $binary_remote_addr zone=general:10m rate=20r/s;

Mejores Prácticas

  1. Defensa en Profundidad: Implementar múltiples capas de seguridad
  2. Principio de Mínimo Privilegio: Otorgar permisos mínimos necesarios
  3. Actualizaciones Regulares: Mantener software actualizado con parches de seguridad
  4. SSL/TLS Fuerte: Usar TLS 1.2+ y cifrados fuertes
  5. Monitorear Logs: Revisar regularmente logs de acceso y errores
  6. Escaneo Automatizado: Implementar escaneo regular de vulnerabilidades
  7. Respaldo de Configuraciones: Mantener respaldos antes de cambios
  8. Probar Cambios: Verificar que las medidas de seguridad no rompan funcionalidad
  9. Documentación: Documentar todas las configuraciones de seguridad
  10. Mantenerse Informado: Seguir avisos de seguridad y mejores prácticas

Conclusión

El hardening de servidores web es esencial para proteger tu infraestructura de amenazas cibernéticas. Al implementar las medidas de seguridad descritas en esta guía—incluyendo ocultar información del servidor, configurar SSL/TLS fuerte, implementar controles de acceso, agregar cabeceras de seguridad y usar Web Application Firewalls—reduces significativamente tu superficie de ataque y mejoras tu postura de seguridad general.

Puntos clave:

  • Ocultar Información: Prevenir divulgación de información sobre versión y configuración del servidor
  • SSL/TLS Fuerte: Usar protocolos modernos y suites de cifrado fuertes
  • Control de Acceso: Implementar restricciones basadas en IP y autenticación
  • Cabeceras de Seguridad: Agregar cabeceras para prevenir ataques web comunes
  • Limitación de Tasa: Proteger contra ataques de fuerza bruta y DDoS
  • Actualizaciones Regulares: Mantener software actualizado con parches de seguridad
  • Monitorear y Probar: Monitorear continuamente logs y probar configuraciones

La seguridad es un proceso continuo, no una tarea única. Revisa y actualiza regularmente tus configuraciones de seguridad, mantente informado sobre nuevas vulnerabilidades e implementa estrategias de defensa en profundidad para proteger tu infraestructura web efectivamente.