Bastionado de un servidor web Apache
Implantación de Aplicaciones Web
1 Bastionado de un servidor web Apache
1.1 Introducción al bastionado (hardening)
El bastionado o endurecimiento de sistemas (hardening) es el conjunto de técnicas, directivas de configuración y buenas prácticas aplicadas a un sistema informático para reducir al mínimo su superficie de exposición y mitigar posibles vulnerabilidades frente a ciberataques.
El servidor web Apache
HTTP Server (denominado comúnmente apache2 en
distribuciones GNU/Linux de la familia Debian y Ubuntu) es uno de los
servidores web más extendidos en Internet. Tras una instalación básica
por defecto, el servidor se entrega configurado para maximizar la
compatibilidad y facilitar una rápida puesta en marcha. No obstante,
esta configuración inicial incluye módulos innecesarios, cabeceras
informativas excesivas y directivas permisivas que resultan inseguras en
un entorno de producción real.
El objetivo de este documento es proporcionar a los estudiantes y administradores de sistemas una guía profesional, completa y realista para securizar un servidor web Apache. Las medidas descritas están alineadas con los estándares internacionales de referencia de la industria, incluyendo:
- CIS (Center for Internet Security),
- NIST (National Institute of Standards and Technology),
- OWASP (Open Web Application Security Project).
1.1.1 Principios fundamentales de seguridad
A la hora de diseñar y mantener la configuración de seguridad de un servidor web debemos guiarnos por cuatro principios clave:
- Principio de menor privilegio (Principle of Least
Privilege): Cada proceso, usuario y servicio debe
ejecutarse exclusivamente con los permisos mínimos e indispensables para
desempeñar su función. El servidor web nunca debe atender peticiones
HTTP/HTTPS bajo el superusuario
root. - Minimización de la superficie de ataque (Attack Surface Reduction): Todo módulo, servicio, método HTTP, puerto o funcionalidad que no sea estrictamente imprescindible debe ser deshabilitado o desinstalado.
- Defensa en profundidad (Defense in Depth): La seguridad no debe depender de una única barrera. Se deben articular múltiples capas superpuestas (cortafuegos de red, control en sistema de ficheros, WAF, TLS robusto, cabeceras HTTP restrictivas y sistemas IPS como Fail2ban).
- No confiar en la seguridad por oscuridad (Security by Obscurity): Aunque ocultar versiones e información técnica dificulta el reconocimiento a escáneres automáticos, la verdadera seguridad reside en configuraciones robustas, cifrados actualizados y gestión continua de parches, no en el mero ocultamiento de nombres o rutas.
1.1.2 Principales amenazas contra servidores web
| Vector de ataque | Descripción | Impacto |
|---|---|---|
| Reconocimiento (fingerprinting) | Identificación de versiones exactas de Apache, sistema operativo y lenguajes backend (PHP). | Facilita la búsqueda y ejecución de exploits públicos (CVEs). |
| Denegación de servicio (DoS / Slowloris) | Agotamiento de procesos e hilos de trabajo mediante el envío lento o masivo de cabeceras/peticiones. | Caída del servicio e indisponibilidad total para usuarios legítimos. |
| Fuga de información y path traversal | Acceso no autorizado a ficheros del
sistema (/etc/passwd), copias de seguridad
(.bak, .sql) o ficheros de configuración
(.git, .env). |
Filtración de credenciales de base de datos, código fuente y datos confidenciales. |
| Ejecución de web shells en subidas | Subida y posterior ejecución de scripts
maliciosos (.php, .phtml) a través de
formularios de subida de archivos. |
Ejecución remota de código (RCE) y toma de control del servidor. |
| Ataques de inyección web (SQLi, XSS, LFI) | Explotación de vulnerabilidades en el código de la aplicación web alojada. | Extracción de bases de datos, alteración de la web y robo de sesiones. |
| Ataques criptográficos a TLS/SSL | Uso de protocolos obsoletos (SSLv3, TLS 1.0, TLS 1.1) o cifrados vulnerables (RC4, 3DES, CBC). | Interceptación y descifrado de credenciales y datos en tránsito (Man-in-the-Middle). |
| Clickjacking / MIME-sniffing | Incrustación del sitio en marcos invisibles (iframes) o manipulación del tipo de contenido por el navegador. | Secuestro de clics, phishing y ejecución de scripts camuflados. |
1.2 Arquitectura y archivos de configuración en Debian/Ubuntu
En las distribuciones GNU/Linux de la familia Debian/Ubuntu, Apache
organiza su configuración en el directorio /etc/apache2/
siguiendo una arquitectura modular y jerárquica gestionada mediante
enlaces simbólicos:
/etc/apache2/
├── apache2.conf # Archivo de configuración maestro principal
├── ports.conf # Definición de puertos de escucha (Listen 80, 443)
├── envvars # Variables de entorno del proceso (usuario, grupo, logs)
├── magic # Firmas para detección de tipos MIME
├── conf-available/ # Fragmentos de configuración global disponibles
│ ├── security.conf # Parámetros de seguridad generales (ServerTokens, etc.)
│ └── security-headers.conf # Cabeceras de seguridad HTTP personalizadas
├── conf-enabled/ # Enlaces simbólicos a conf-available/ activos
├── mods-available/ # Módulos compilados disponibles en el sistema
├── mods-enabled/ # Enlaces simbólicos a mods-available/ activos
├── sites-available/ # Archivos de configuración de VirtualHosts disponibles
│ ├── 000-default.conf # VirtualHost HTTP por defecto (o catch-all)
│ └── default-ssl.conf # VirtualHost HTTPS por defecto
└── sites-enabled/ # Enlaces simbólicos a sites-available/ activos
1.2.1 Comandos de administración de Apache
Para gestionar configuraciones, módulos y sitios web de forma limpia y mantenible, se utilizan las herramientas nativas de Debian/Ubuntu:
# Gestión de sitios web (VirtualHosts)
sudo a2ensite <nombre-sitio>.conf
sudo a2dissite <nombre-sitio>.conf
# Gestión de módulos
sudo a2enmod <nombre-modulo>
sudo a2dismod <nombre-modulo>
# Gestión de fragmentos de configuración global
sudo a2enconf <nombre-configuracion>
sudo a2disconf <nombre-configuracion>
# Comprobación de sintaxis de la configuración (IMPRESCINDIBLE antes de reiniciar)
sudo apache2ctl configtest
# Recarga (sin corte de servicio) o reinicio del servicio
sudo systemctl reload apache2
sudo systemctl restart apache2[!IMPORTANT] Ejecuta siempre
sudo apache2ctl configtest(osudo apachectl -t) antes de recargar o reiniciar el servicio Apache. Si existe algún error sintáctico o una directiva incompatible, este comando te advertirá de inmediato y evitará una caída inesperada del servicio en producción.
1.3 Mantenimiento del sistema y permisos del sistema de ficheros
1.3.1 Actualización continua del software
El primer paso fundamental en cualquier procedimiento de bastionado consiste en mantener el sistema operativo y el software del servidor actualizados con los últimos parches de seguridad:
sudo apt update
sudo apt upgrade -yPara consultar la versión instalada de Apache y los módulos compilados de forma estática:
apache2 -v
apachectl -V1.3.2 Usuario y grupo de ejecución sin privilegios
Cuando el sistema operativo arranca, el proceso maestro de Apache se
inicia como superusuario root con el único propósito de
enlazar los puertos privilegiados TCP 80 y 443. Inmediatamente después,
el servidor genera procesos hijos o hilos de trabajo (worker
threads) que se ejecutan bajo un usuario sin privilegios.
En Ubuntu y Debian, este usuario y grupo se configuran en
/etc/apache2/envvars:
export APACHE_RUN_USER=www-data
export APACHE_RUN_GROUP=www-dataPodemos verificar que los procesos de atención de peticiones se
ejecutan bajo www-data mediante el comando
ps:
ps aux | grep apache2La salida mostrará un único proceso principal perteneciente a
root y múltiples procesos trabajadores pertenecientes a
www-data.
[!CAUTION] Nunca cambies
APACHE_RUN_USERarootni permitas que los procesos hijos atiendan peticiones con privilegios de administración. Si un atacante lograra ejecutar código remoto a través de una vulnerabilidad web, obtendría acceso total e inmediato como superusuario a toda la máquina.
1.3.3 Jerarquía de permisos y propiedad en el sistema de ficheros
Un error clásico de administración consiste en otorgar permisos
777 o asignar la propiedad total del
DocumentRoot (/var/www/html) al usuario
www-data. Si el servidor web tiene permisos de escritura en
todos los archivos, un atacante que explote una vulnerabilidad en una
aplicación PHP podría sobrescribir ficheros .php, inyectar
puertas traseras (web shells) o modificar archivos de
configuración.
1.3.3.1 Permisos recomendados para
la configuración de Apache (/etc/apache2)
Los archivos de configuración de /etc/apache2 deben
pertenecer exclusivamente a root:root y no ser modificables
por el usuario www-data:
sudo chown -R root:root /etc/apache2
sudo find /etc/apache2 -type d -exec chmod 755 {} \;
sudo find /etc/apache2 -type f -exec chmod 644 {} \;[!WARNING] Protección estricta de claves privadas TLS/SSL: Las claves privadas criptográficas (
.key) nunca deben tener permisos644. Si almacenas certificados y claves privadas en/etc/ssl/privateo dentro de/etc/apache2/ssl/, asegúrate de que las claves privadas pertenezcan aroot:ssl-certoroot:rootcon permisos600o640, de modo que ningún usuario no autorizado del sistema pueda leerlas.
1.3.3.2 Permisos recomendados para
el directorio web (DocumentRoot)
- Los directorios deben tener permisos
755(rwxr-xr-x) o750en entornos con múltiples usuarios locales. - Los ficheros regulares deben tener permisos
644(rw-r--r--) o640. - El propietario de los archivos debe ser
rooto un usuario de despliegue administrativo (deploy), perteneciendo al grupowww-data. - Únicamente los directorios destinados explícitamente a la subida de
archivos (por ejemplo,
uploads/omedia/) deben tener permisos de escritura parawww-data.
# Establecer propietario y grupo
sudo chown -R root:www-data /var/www/html
# Ajustar permisos estándar para directorios y archivos
sudo find /var/www/html -type d -exec chmod 755 {} \;
sudo find /var/www/html -type f -exec chmod 644 {} \;
# Directorios de subida específicos que requieren escritura:
sudo chown -R www-data:www-data /var/www/html/uploads
sudo chmod -R 755 /var/www/html/uploads1.3.4 Protección contra la ejecución de scripts en directorios de subidas (uploads)
Una de las técnicas más frecuentes de intrusión consiste en
aprovechar un formulario de subida de ficheros para subir un script PHP
malicioso (por ejemplo shell.php o c99.php) a
la carpeta uploads/ y solicitarlo vía HTTP para obtener una
terminal interactiva.
Aunque la carpeta tenga permisos de escritura para
www-data, debemos prohibir taxativamente a Apache que
ejecute cualquier tipo de script en ese directorio.
Añadimos la siguiente directiva dentro de la configuración del
VirtualHost o en
/etc/apache2/conf-available/security.conf:
# Bloquear la ejecución de scripts en directorios de subida de archivos
<Directory "/var/www/html/uploads">
# Desactivar ejecución de scripts CGI e includes
Options -ExecCGI -Includes
# Denegar acceso directo a cualquier extensión ejecutable
<FilesMatch "(?i)\.(php|phtml|phar|php3|php4|php5|php7|php8|cgi|pl|py|sh|jsp|asp|exe)$">
Require all denied
</FilesMatch>
# Forzar a Apache a tratar cualquier fichero restante como estático
ForceType application/octet-stream
<IfModule mod_php.c>
php_admin_flag engine off
</IfModule>
</Directory>Con esta regla, incluso si un atacante consigue subir un fichero
.php, cualquier intento de solicitarlo devolverá un error
403 Forbidden y el código nunca será ejecutado por el
servidor.
1.4 Ocultación de información del servidor (information disclosure)
Por defecto, Apache incluye en la cabecera HTTP Server y
en los mensajes de error el nombre del servidor, la versión exacta de
Apache, el sistema operativo de base y las versiones de los módulos
instalados (por ejemplo:
Apache/2.4.58 (Ubuntu) OpenSSL/3.0.13 PHP/8.3.6). Esta
información facilita la fase de reconocimiento (fingerprinting)
a posibles atacantes.
| Configuración | Cabecera HTTP Server
emitida |
Nivel de exposición |
|---|---|---|
| Por defecto (Insegura) | Server: Apache/2.4.58 (Ubuntu) mod_ssl/2.4.58 OpenSSL/3.0.13 PHP/8.3.6 |
Inseguro / Crítico (expone versiones de Apache, SO, OpenSSL y PHP) |
| Bastionada (Segura) | Server: Apache |
Seguro (mínimo permitido por el estándar HTTP) |
1.4.1 Configuración de
ServerTokens y ServerSignature
Para limitar al mínimo la información expuesta, editamos el archivo
/etc/apache2/conf-available/security.conf:
# Opciones disponibles para ServerTokens:
# Full -> Apache/2.4.58 (Ubuntu) PHP/8.3.6 mod_ssl/2.4.58
# OS -> Apache/2.4.58 (Ubuntu)
# Minor -> Apache/2.4
# Min -> Apache/2.4.58
# Prod -> Apache (Mínima información permitida por el estándar HTTP)
ServerTokens Prod
ServerSignature OffServerTokens Prod: Configura la cabecera HTTPServerpara que devuelva únicamente la palabra genéricaApache, ocultando la versión exacta, la distribución Linux y los módulos.ServerSignature Off: Desactiva el pie de página que Apache genera en las páginas de error (404, 403, 500) donde tradicionalmente se mostraba la versión, el nombre del host y el puerto de escucha.
1.4.2 Ocultar la cabecera
X-Powered-By
Los intérpretes de backend como PHP añaden por defecto la cabecera
X-Powered-By: PHP/8.x.x. Debemos desactivarla en el archivo
de configuración php.ini correspondiente:
; En /etc/php/8.x/apache2/php.ini o /etc/php/8.x/fpm/php.ini
expose_php = OffAdicionalmente, podemos forzar a Apache a eliminar cualquier cabecera
X-Powered-By residual generada por aplicaciones o proxies
inversos mediante mod_headers:
# Requiere: sudo a2enmod headers
Header always unset X-Powered-By
Header unset X-Powered-By1.4.3 Personalización de páginas de
error (ErrorDocument)
Las páginas de error estándar de Apache pueden revelar detalles sobre la estructura interna del servidor y rutas del sistema operativo. Es una buena práctica redirigir los errores comunes a documentos HTML genéricos y amigables:
# En /etc/apache2/conf-available/security.conf o dentro de cada VirtualHost
ErrorDocument 400 /errores/400.html
ErrorDocument 401 /errores/401.html
ErrorDocument 403 /errores/403.html
ErrorDocument 404 /errores/404.html
ErrorDocument 500 /errores/500.html1.4.4 Eliminación de la página por defecto de Apache
La página predeterminada de instalación
(/var/www/html/index.html) indica que el servidor acaba de
ser instalado y expone la estructura de archivos de Ubuntu/Debian.
Debemos sustituirla por el contenido real de la aplicación o
eliminarla:
sudo rm /var/www/html/index.html1.5 Control de acceso y directivas de directorio seguras
El control de acceso al sistema de archivos es una de las defensas más críticas de Apache. Si no se restringe adecuadamente, un atacante podría solicitar archivos del sistema base fuera del directorio web a través de vulnerabilidades de cruce de directorios (Directory Traversal).
1.5.1 Política restrictiva global por defecto
En el archivo principal /etc/apache2/apache2.conf,
debemos asegurarnos de que la directiva para la raíz del sistema de
ficheros (/) bloquee todo el tráfico por defecto:
<Directory />
Options None
AllowOverride None
Require all denied
</Directory>Esta directiva implementa el principio de denegación por defecto
(deny all by default): ningún usuario web puede leer
absolutamente nada del disco salvo que se autorice explícitamente en un
bloque <Directory> posterior.
1.5.2 Configuración restrictiva del
DocumentRoot
Para el directorio donde residen las páginas web públicas
(/var/www/html), configuramos permisos selectivos:
<Directory /var/www/html>
Options -Indexes -FollowSymLinks +SymLinksIfOwnerMatch -Includes -ExecCGI
AllowOverride None
Require all granted
</Directory>Analicemos en detalle cada opción de seguridad:
-Indexes: Desactiva el listado automático de directorios. Si un usuario accede a una carpeta que no contiene un ficheroindex.htmloindex.php, Apache no mostrará el listado de archivos contenidos, devolviendo un error403 Forbidden. Esto previene la enumeración de archivos de la aplicación.-FollowSymLinks +SymLinksIfOwnerMatch: Desactiva el seguimiento incondicional de enlaces simbólicos. ConSymLinksIfOwnerMatch, Apache solo seguirá un enlace simbólico si el propietario del enlace coincide con el propietario del archivo destino, evitando que un usuario web cree un enlace simbólico que apunte a/etc/passwdo/etc/shadow.-Includes: Desactiva los Server Side Includes (SSI), evitando la inyección de directivas del lado del servidor en archivos HTML.-ExecCGI: Deshabilita la ejecución de scripts CGI arbitrarios en este directorio.AllowOverride None: Deshabilita el uso de archivos.htaccess. Los archivos.htaccessreducen el rendimiento del servidor (Apache debe inspeccionar cada directorio en cada petición) y permiten a usuarios locales anular directivas de seguridad. Toda la configuración debe residir en los archivos principales del servidor.
[!WARNING] Si tu aplicación (por ejemplo, WordPress o Drupal) necesita reglas de reescritura de URLs mediante
.htaccess, limitaAllowOverrideúnicamente a lo necesario, comoAllowOverride FileInfo Limit Options=SymLinksIfOwnerMatchen lugar deAllowOverride All.
1.5.3 Bloqueo de archivos ocultos, ficheros de configuración y copias de seguridad
Es habitual que durante el despliegue de aplicaciones queden
expuestos archivos sensibles de control de versiones
(.git), variables de entorno (.env), volcados
de bases de datos (.sql) o copias de seguridad de editores
(.bak, .swp).
Podemos bloquear globalmente el acceso a todos estos patrones
añadiendo la siguiente configuración en
/etc/apache2/conf-available/security.conf:
# Bloquear acceso a archivos y directorios ocultos (.git, .env, .htaccess)
<FilesMatch "^\.">
Require all denied
</FilesMatch>
# Excepción explícita para el reto HTTP-01 de Let's Encrypt / Certbot (.well-known)
<Directory "/var/www/html/.well-known">
Require all granted
</Directory>
# Bloquear extensiones de archivos sensibles, volcados y copias de seguridad
<FilesMatch "(?i)\.(bak|config|sql|fla|psd|ini|log|sh|env|swp|dist|inc|yaml|yml|md|tpl)$">
Require all denied
</FilesMatch>1.5.4 Configuración de un VirtualHost por defecto (catch-all / blackhole)
Cuando un atacante escanea rangos de direcciones IP o envía
peticiones con una cabecera Host manipulada (Host
Header Injection), Apache recurre por defecto al primer VirtualHost
cargado en orden alfabético (generalmente
000-default.conf).
Para neutralizar escaneos masivos y evitar fugas de información, se
recomienda configurar un VirtualHost por defecto atrapa-todo
(catch-all) que capture cualquier petición dirigida
directamente a la dirección IP o con un nombre de dominio desconocido,
respondiendo de inmediato con un error 403 Forbidden o
400 Bad Request:
# /etc/apache2/sites-available/000-catchall.conf
<VirtualHost *:80>
ServerName default
ServerAlias *
# Denegar cualquier petición no dirigida a un dominio autorizado
<Location />
Require all denied
</Location>
ErrorLog ${APACHE_LOG_DIR}/catchall_error.log
CustomLog ${APACHE_LOG_DIR}/catchall_access.log combined
</VirtualHost>Posteriormente, habilitamos este sitio como el primero de la lista
con sudo a2ensite 000-catchall.conf. De este modo, los
VirtualHosts legítimos solo responderán cuando la cabecera
Host coincida exactamente con su ServerName o
ServerAlias configurado.
1.6 Arquitectura MPM y desactivación de módulos innecesarios
Cada módulo cargado en Apache consume memoria RAM y añade código que puede contener vulnerabilidades de seguridad potenciales. Siguiendo el principio de minimización, debemos auditar y desactivar todos los módulos que no sean indispensables.
1.6.1 Selección del MPM:
modernización con mpm_event y PHP-FPM
En versiones modernas de Apache (2.4+) sobre Debian/Ubuntu, la
arquitectura recomendada consiste en utilizar el módulo de
multiprocesamiento mpm_event junto con
PHP-FPM a través de mod_proxy_fcgi, en
lugar del módulo obsoleto mpm_prefork con
libapache2-mod-php.
| Característica | mpm_prefork +
libapache2-mod-php (Obsoleto) |
mpm_event + PHP-FPM /
proxy_fcgi (Recomendado) |
|---|---|---|
| Modelo de concurrencia | Proceso pesado dedicado por conexión | Hilos asíncronos ligeros sin bloqueo |
| Consumo de memoria | Muy alto (duplica el intérprete PHP en cada proceso) | Mínimo y optimizado |
| Resistencia DoS/Slowloris | Muy baja (agotamiento rápido de procesos) | Muy alta (descriptores de socket no bloqueantes) |
| Aislamiento de seguridad | PHP se ejecuta en el mismo espacio que Apache | PHP aislado en un proceso/socket Unix independiente |
| Soporte HTTP/2 | No compatible | Soporte nativo completo |
Para migrar a mpm_event y PHP-FPM:
# Deshabilitar módulo PHP clásico y MPM prefork
sudo a2dismod php8.x mpm_prefork
# Habilitar MPM event, proxy FastCGI y configuración PHP-FPM
sudo a2enmod mpm_event proxy proxy_fcgi setenvif
sudo a2enconf php8.x-fpm
sudo systemctl restart apache21.6.2 Auditoría de módulos activos
Para listar todos los módulos compilados y cargados actualmente en memoria:
apache2ctl -M1.6.3 Módulos potencialmente peligrosos o innecesarios
A continuación se detallan los módulos que deben revisarse o desactivarse en la mayoría de entornos de producción:
| Módulo | Función | Riesgo de seguridad | Acción recomendada |
|---|---|---|---|
mod_autoindex |
Genera listados HTML de directorios. | Facilita la enumeración de archivos y carpetas del servidor. | Desactivar
(a2dismod autoindex). |
mod_info |
Muestra la configuración completa del
servidor en /server-info. |
Fuga crítica de información y rutas internas. | Desactivar en producción
(a2dismod info). |
mod_status |
Muestra estadísticas y peticiones activas
en /server-status. |
Fuga de IPs de clientes, URLs consultadas y carga del sistema. | Restringir por IP o desactivar. |
mod_userdir |
Mapea URLs tipo /~usuario/ al
directorio /home/usuario/public_html. |
Facilita la enumeración de usuarios locales del sistema Linux. | Desactivar
(a2dismod userdir). |
mod_cgi /
mod_cgid |
Ejecuta scripts CGI tradicionales en
/cgi-bin/. |
Riesgo de ejecución de código y consumo excesivo de recursos. | Desactivar si se usa PHP-FPM
(a2dismod cgi cgid). |
mod_include |
Ejecuta directivas Server Side Includes (SSI). | Riesgo de inyección de código del lado del servidor. | Desactivar si no se usa
(a2dismod include). |
mod_dav /
mod_dav_fs |
Protocolo WebDAV para gestión remota de archivos. | Riesgo de subida y modificación no autorizada de ficheros. | Desactivar si no se requiere
(a2dismod dav dav_fs). |
Para desactivar los módulos innecesarios de forma segura:
sudo a2dismod autoindex status info userdir cgi cgid include dav dav_fs
sudo systemctl restart apache2[!CAUTION] Si utilizas el módulo
mod_proxy, verifica que la directivaProxyRequests Offesté establecida a nivel global. DejarProxyRequests Onconvierte tu servidor en un Proxy Abierto (Open Proxy), permitiendo a ciberdelincuentes utilizar tu infraestructura como pasarela anónima para lanzar ataques a terceros.
1.6.4 Configuración segura de
mod_status
Si requieres mantener activo mod_status para
herramientas de monitorización interna (como Prometheus, Zabbix o
Nagios), debes restringir estrictamente el acceso para que solo responda
a peticiones desde localhost o desde la IP específica del
servidor de monitorización:
# En /etc/apache2/mods-available/status.conf
<IfModule mod_status.c>
<Location /server-status>
SetHandler server-status
Require local
Require ip 192.168.1.50
</Location>
ExtendedStatus On
</IfModule>1.7 Restricción de métodos HTTP
El protocolo HTTP define diversos métodos de petición
(GET, POST, HEAD,
PUT, DELETE, OPTIONS,
TRACE, PATCH, CONNECT). La
inmensa mayoría de sitios web estándar únicamente necesitan procesar
peticiones GET, POST y HEAD.
1.7.1 Desactivar el método HTTP TRACE (cross-site tracing)
El método TRACE se diseñó para depuración de red: el
servidor web devuelve al cliente el contenido exacto de la petición
recibida. Sin embargo, este comportamiento permite a un atacante que
ejecute código JavaScript (vía XSS) eludir la protección de cookies
marcadas como HttpOnly mediante técnicas de Cross-Site
Tracing (XST).
Para desactivar el método TRACE en todo el servidor,
editamos /etc/apache2/conf-available/security.conf:
TraceEnable Off1.7.2 Limitar métodos permitidos a nivel de directorio
Podemos restringir de forma estricta los métodos admitidos en el
DocumentRoot mediante la directiva
<LimitExcept>:
<Directory /var/www/html>
# Si la aplicación web utiliza APIs o peticiones CORS, incluye OPTIONS
<LimitExcept GET POST HEAD OPTIONS>
Require all denied
</LimitExcept>
</Directory>Si la aplicación ofrece una API REST que requiere métodos como
PUT, DELETE o PATCH, dichos
métodos deben autorizarse exclusivamente dentro del bloque
<Location /api> correspondiente, manteniéndolos
bloqueados en el resto del sitio:
<Location /api>
<LimitExcept GET POST PUT DELETE PATCH OPTIONS HEAD>
Require all granted
</LimitExcept>
</Location>1.8 Implementación de cabeceras de seguridad HTTP (HTTP security headers)
Las cabeceras de seguridad HTTP son instrucciones que el servidor web envía en la respuesta HTTP para obligar al navegador del cliente a activar mecanismos de protección integrados. Su correcta implementación mitiga ataques tan extendidos como el Clickjacking, Cross-Site Scripting (XSS), inyección de datos y MIME-sniffing.
Para gestionar cabeceras en Apache, es imprescindible habilitar el
módulo mod_headers:
sudo a2enmod headersA continuación, crearemos un archivo de configuración dedicado
/etc/apache2/conf-available/security-headers.conf:
# /etc/apache2/conf-available/security-headers.conf
<IfModule mod_headers.c>
# 1. HTTP Strict Transport Security (HSTS) - Solo sobre conexiones HTTPS
<If "%{HTTPS} == 'on'">
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
</If>
# 2. Protección contra Clickjacking
Header always set X-Frame-Options "SAMEORIGIN"
# 3. Protección contra MIME-Sniffing
Header always set X-Content-Type-Options "nosniff"
# 4. Política de Referrer
Header always set Referrer-Policy "strict-origin-when-cross-origin"
# 5. Restricción de APIs y Hardware del Navegador (Permissions-Policy)
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=(), usb=()"
# 6. Aislamiento de Origen Cruzado (COOP y CORP)
Header always set Cross-Origin-Opener-Policy "same-origin"
Header always set Cross-Origin-Resource-Policy "same-origin"
# 7. Content Security Policy (CSP)
Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'self'; form-action 'self'; base-uri 'self';"
# 8. Desactivar el filtro XSS obsoleto y propenso a vulnerabilidades en navegadores antiguos
Header always set X-XSS-Protection "0"
# 9. Asegurar Cookies de Sesión (Inyectar Secure, HttpOnly y SameSite)
Header edit Set-Cookie ^(.*)$ "$1; Secure; HttpOnly; SameSite=Lax"
</IfModule>Habilitamos la configuración y recargamos Apache:
sudo a2enconf security-headers
sudo apache2ctl configtest
sudo systemctl reload apache21.8.1 Descripción detallada de las cabeceras de seguridad
| Cabecera HTTP | Propósito y mitigación de seguridad |
|---|---|
| Strict-Transport-Security (HSTS) | Obliga al navegador a usar siempre HTTPS durante el tiempo indicado (31536000s = 1 año), impidiendo ataques de degradación SSL Stripping. |
| X-Frame-Options | Evita que el sitio sea incrustado en
<iframe> o <frame> externos,
neutralizando por completo ataques de Clickjacking. |
| X-Content-Type-Options | Fija el valor nosniff,
impidiendo que el navegador intente adivinar el tipo MIME de un fichero
y ejecute scripts camuflados como imágenes. |
| Referrer-Policy | Controla qué información de la URL de
origen se envía en la cabecera Referer al navegar hacia
enlaces externos, protegiendo tokens y rutas sensibles. |
| Permissions-Policy | Desactiva el acceso a APIs de hardware sensibles del cliente como la cámara, el micrófono, el sensor de geolocalización o pasarelas de pago. |
| Content-Security-Policy (CSP) | Especifica exactamente de qué orígenes autorizados el navegador puede cargar scripts, estilos, imágenes y fuentes. Máxima protección frente a XSS e inyecciones. |
| SameSite / Secure / HttpOnly en Set-Cookie | Protege las cookies de sesión contra robo
mediante XSS (HttpOnly), interceptación en tránsito
(Secure) y ataques CSRF (SameSite=Lax). |
1.8.2 Verificación de cabeceras con
curl
Podemos comprobar rápidamente desde el terminal que nuestro servidor emite todas las cabeceras correctamente:
curl -I https://midominio.com1.9 Configuración robusta de SSL/TLS (HTTPS seguro)
El cifrado en tránsito mediante el protocolo HTTPS es obligatorio en la web actual. No obstante, habilitar HTTPS no es suficiente por sí solo: es necesario garantizar que la configuración criptográfica utilice únicamente protocolos y algoritmos seguros.
1.9.1 Habilitación de módulos criptográficos y rendimiento
# Módulos SSL, almacenamiento en caché de sesiones y soporte para HTTP/2
sudo a2enmod ssl
sudo a2enmod socache_shmcb
sudo a2enmod http21.9.2 Selección de protocolos y conjuntos de cifrado (cipher suites)
Debemos deshabilitar de forma categórica protocolos vulnerables como SSLv2, SSLv3, TLS 1.0 y TLS 1.1, permitiendo exclusivamente TLS 1.2 y TLS 1.3.
Editamos el archivo global de configuración SSL
/etc/apache2/mods-available/ssl.conf o la configuración de
nuestro VirtualHost HTTPS:
# Protocolos permitidos (Solo TLS 1.2 y TLS 1.3)
SSLProtocol -all +TLSv1.2 +TLSv1.3
# Cifrados seguros para TLS 1.2 (con secreto perfecto hacia adelante - PFS)
SSLCipherSuite 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
# Preferencia de cifrados (en OpenSSL moderno con TLS 1.3 se recomienda off)
SSLHonorCipherOrder off
# Desactivar compresión SSL para neutralizar ataques CRIME / BREACH
SSLCompression off
# Desactivar Session Tickets si no son estrictamente necesarios
SSLSessionTickets off1.9.3 Grapado OCSP (OCSP stapling)
El grapado OCSP (OCSP stapling) mejora significativamente el rendimiento y la privacidad del usuario. En lugar de que cada navegador contacte con la Autoridad de Certificación (CA) para comprobar si el certificado ha sido revocado, el propio servidor web Apache consulta periódicamente el estado de revocación a la CA y adjunta la respuesta firmada directamente durante el saludo TLS (TLS Handshake).
Añadimos la siguiente configuración a nivel global (en
/etc/apache2/conf-available/ssl-stapling.conf):
<IfModule mod_ssl.c>
SSLUseStapling on
SSLStaplingCache "shmcb:${APACHE_RUN_DIR}/ssl_stapling(32768)"
SSLStaplingResponseTime 5
SSLStaplingResponderTimeout 5
SSLStaplingReturnUntrusted off
</IfModule>1.9.4 Habilitación de HTTP/2
El protocolo HTTP/2 ofrece mejoras drásticas de rendimiento (multiplexación de peticiones sobre una única conexión TCP, compresión de cabeceras HPACK) y exige de forma obligatoria el uso de TLS moderno:
# En el archivo de VirtualHost o a nivel global
Protocols h2 http/1.11.9.5 Redirección obligatoria de HTTP a HTTPS
Todo el tráfico que llegue al puerto TCP 80 debe ser redirigido
inmediatamente al puerto seguro 443 con un código de estado
301 Moved Permanently:
# /etc/apache2/sites-available/000-default.conf
<VirtualHost *:80>
ServerName midominio.com
ServerAlias www.midominio.com
# Redirección permanente a HTTPS preservando la ruta solicitada
Redirect permanent / https://midominio.com/
</VirtualHost>1.10 Protección contra denegación de servicio (DoS) y agotamiento de recursos
Un servidor web Apache mal parametrizado puede ser fácilmente inutilizado mediante ataques de Denegación de Servicio basados en el agotamiento de descriptores de sockets, procesos y memoria (Slowloris, Slow HTTP POST o inundaciones de peticiones).
1.10.1 Ajuste de tiempos de espera (timeouts) y conexiones persistentes
En /etc/apache2/apache2.conf, reducimos los tiempos de
espera excesivos por defecto:
# Tiempo máximo (en segundos) que Apache esperará para recibir una petición
Timeout 30
# Habilitar conexiones HTTP persistentes (Keep-Alive)
KeepAlive On
# Número máximo de peticiones por conexión persistente
MaxKeepAliveRequests 100
# Tiempo de espera (en segundos) para la siguiente petición en la misma conexión
KeepAliveTimeout 51.10.2 Limitación del tamaño de peticiones y cabeceras
Para prevenir desbordamientos de búfer y subidas masivas de datos que consuman el ancho de banda del servidor, establecemos límites estrictos:
# Limita el tamaño del cuerpo de la petición HTTP a 10 MB (10485760 bytes)
# Ajustar según las necesidades reales de subida de la aplicación
LimitRequestBody 10485760
# Limita el tamaño de la línea de petición HTTP (URI) a 4094 bytes
LimitRequestLine 4094
# Limita el número de campos en las cabeceras HTTP a 50
LimitRequestFields 50
# Limita el tamaño máximo de cada campo de cabecera a 8190 bytes
LimitRequestFieldSize 81901.10.3 Mitigación de Slowloris con
mod_reqtimeout
El ataque Slowloris mantiene abiertas miles de
conexiones HTTP enviando cabeceras a una velocidad extremadamente lenta
(1 byte cada pocos segundos), agotando todos los hilos de Apache. El
módulo nativo mod_reqtimeout neutraliza esta técnica
exigiendo un tiempo máximo y una tasa mínima de transferencia de
datos:
sudo a2enmod reqtimeoutConfiguramos en
/etc/apache2/mods-available/reqtimeout.conf:
<IfModule mod_reqtimeout.c>
# Espera un máximo de 20s a 40s para recibir cabeceras; si la tasa es menor de 500 bytes/s, cancela la conexión
RequestReadTimeout header=20-40,MinRate=500 body=20,MinRate=500
</IfModule>1.10.4 Prevención de inundaciones
con mod_evasive
mod_evasive proporciona protección frente a ataques de
fuerza bruta, escaneo masivo de URLs y ataques DoS HTTP en capa de
aplicación.
sudo apt install libapache2-mod-evasive -yConfiguramos
/etc/apache2/mods-available/evasive.conf:
<IfModule mod_evasive20.c>
# Tamaño de la tabla hash interna
DOSHashTableSize 3097
# Número máximo de peticiones a una misma página en el intervalo (por defecto 1s)
DOSPageCount 10
DOSPageInterval 1
# Número máximo de peticiones totales a un mismo sitio en el intervalo (por defecto 1s)
DOSSiteCount 100
DOSSiteInterval 1
# Tiempo de bloqueo en segundos para una IP infractora (recibirá error 403 Forbidden)
DOSBlockingPeriod 60
# Directorio para registrar bloqueos temporales
DOSLogDir "/var/log/mod_evasive"
# Lista blanca de IPs que no deben ser bloqueadas (por ejemplo localhost o monitorización)
DOSWhitelist 127.0.0.1
</IfModule>[!TIP] Ajuste realista de umbrales en
mod_evasive: En sitios web modernos con abundantes elementos estáticos (múltiples archivos CSS, JS, fuentes e imágenes), un único acceso de un usuario legítimo puede disparar más de 40 peticiones simultáneas. EstablecerDOSSiteCountpor debajo de 50 provocaría falsos positivos (bloqueo a usuarios legítimos). Valores deDOSPageCount 10yDOSSiteCount 100ofrecen un equilibrio robusto y realista.
Creamos el directorio de logs con los permisos adecuados:
sudo mkdir -p /var/log/mod_evasive
sudo chown -R www-data:www-data /var/log/mod_evasive
sudo a2enmod evasive
sudo systemctl restart apache21.11 Cortafuegos de aplicaciones web (WAF): ModSecurity y OWASP CRS
Un WAF (Web Application Firewall) opera en la capa 7 del modelo OSI (capa de aplicación), inspeccionando en tiempo real tanto el tráfico HTTP entrante como las respuestas salientes del servidor.
Mientras que un cortafuegos tradicional (como UFW o iptables) solo filtra puertos e IPs, ModSecurity analiza el contenido de las peticiones para detectar y bloquear patrones de inyección SQL (SQLi), Cross-Site Scripting (XSS), inclusión de archivos locales y remotos (LFI/RFI), y ataques contra vulnerabilidades de día cero (0-days).
1.11.1 Instalación de ModSecurity
En Ubuntu y Debian instalamos el módulo oficial:
sudo apt install libapache2-mod-security2 -y1.11.2 Activación del motor de reglas y ciclo de vida en producción
Por defecto, ModSecurity viene configurado en modo solo detección
(DetectionOnly). En entornos profesionales se recomienda
seguir este procedimiento:
- Fase de detección (staging): Mantener
SecRuleEngine DetectionOnlydurante unos días para registrar las peticiones legítimas y detectar posibles falsos positivos. - Exclusión de falsos positivos: Si alguna regla del
CRS bloquea una funcionalidad legítima (como la edición de entradas en
WordPress o subida de ficheros JSON), se desactiva puntualmente esa
regla mediante
SecRuleRemoveById <ID_REGLA>. - Fase de bloqueo (production): Activar el
motor en modo de bloqueo
SecRuleEngine On.
# Copiar el archivo de plantilla recomendado
sudo cp /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf
# Habilitar el motor de bloqueo (SecRuleEngine On)
sudo sed -i 's/SecRuleEngine DetectionOnly/SecRuleEngine On/' /etc/modsecurity/modsecurity.conf1.11.3 Integración del OWASP ModSecurity Core Rule Set (CRS)
El OWASP CRS es el conjunto de reglas de seguridad más reconocido y mantenido del mundo para proteger servidores web.
Instalamos el paquete del CRS en el sistema:
sudo apt install modsecurity-crs -yVerificamos en
/etc/apache2/mods-available/security2.conf que las reglas
del CRS se carguen adecuadamente:
<IfModule security2_module>
SecDataDir /var/cache/modsecurity
IncludeOptional /etc/modsecurity/*.conf
IncludeOptional /usr/share/modsecurity-crs/*.conf
IncludeOptional /usr/share/modsecurity-crs/rules/*.conf
</IfModule>Reiniciamos el servicio:
sudo apache2ctl configtest
sudo systemctl restart apache21.11.4 Inspección de registros forenses de ModSecurity
Cualquier ataque bloqueado quedará detalladamente registrado en el archivo de auditoría:
sudo tail -f /var/log/apache2/modsec_audit.log1.12 Detección y bloqueo de intrusiones con Fail2Ban
Fail2Ban es un sistema de prevención de intrusiones
(IPS) que monitoriza continuamente los archivos de registro
(logs) de Apache y del sistema operativo. Cuando detecta
múltiples intentos de acceso fallidos, escaneos de vulnerabilidades o
patrones anómalos procedentes de una misma dirección IP, añade
automáticamente una regla en el cortafuegos de red
(nftables o iptables) para bloquear el tráfico
de esa IP durante un tiempo determinado.
1.12.1 Instalación de Fail2Ban
sudo apt install fail2ban -y1.12.2 Configuración de jaulas (jails) para Apache
En lugar de modificar el archivo original
/etc/fail2ban/jail.conf, creamos una copia de configuración
personalizada en /etc/fail2ban/jail.local:
# /etc/fail2ban/jail.local
[DEFAULT]
# Tiempo de baneo por defecto: 1 hora (3600 segundos)
bantime = 3600
# Ventana de tiempo para contar reintentos: 10 minutos (600 segundos)
findtime = 600
# Número máximo de intentos antes del baneo
maxretry = 5
# IPs en lista blanca que nunca serán bloqueadas
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24
# 1. Protección contra fuerza bruta en autenticación básica HTTP
[apache-auth]
enabled = true
port = http,https
logpath = %(apache_error_log)s
# 2. Bloqueo de escáneres maliciosos y bots dañinos
[apache-badbots]
enabled = true
port = http,https
logpath = %(apache_access_log)s
bantime = 86400
maxretry = 1
# 3. Bloqueo de escaneos a scripts inexistentes (.php, .asp, .cgi)
[apache-noscript]
enabled = true
port = http,https
logpath = %(apache_error_log)s
maxretry = 3
# 4. Bloqueo de intentos de desbordamiento de búfer en URIs
[apache-overflows]
enabled = true
port = http,https
logpath = %(apache_error_log)s
maxretry = 2
# 5. Integración con ModSecurity (baneo automático de atacantes detectados por el WAF)
[apache-modsecurity]
enabled = true
port = http,https
logpath = /var/log/apache2/modsec_audit.log
maxretry = 2Iniciamos y habilitamos el servicio:
sudo systemctl enable fail2ban
sudo systemctl restart fail2ban1.12.3 Comandos de supervisión de Fail2Ban
Para comprobar el estado de las jaulas y consultar las IPs actualmente bloqueadas:
# Ver estado general y jaulas activas
sudo fail2ban-client status
# Ver detalle de una jaula específica (ej. apache-auth o apache-noscript)
sudo fail2ban-client status apache-auth
# Desbloquear manualmente una IP baneada por error
sudo fail2ban-client set apache-auth unbanip 192.168.1.1001.13 Gestión, monitorización y auditoría de registros (logs)
Los registros de actividad (logs) constituyen la principal fuente de información forense ante un incidente de seguridad y son indispensables para la monitorización continua.
1.13.1 Formato enriquecido de registros y soporte para proxies inversos
En entornos donde Apache se encuentra tras un balanceador de carga,
CDN o proxy inverso (como Cloudflare, HAProxy o Nginx), la IP registrada
por defecto sería la del propio proxy. Es fundamental registrar la IP
real del cliente activando el módulo mod_remoteip:
sudo a2enmod remoteipConfiguramos en
/etc/apache2/conf-available/remoteip.conf:
<IfModule mod_remoteip.c>
RemoteIPHeader X-Forwarded-For
# Declarar rangos de confianza de tus proxies/balanceadores internos
RemoteIPInternalProxy 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 127.0.0.1
</IfModule>En /etc/apache2/apache2.conf, definimos un formato de
log enriquecido que incluya el tiempo de respuesta del servidor en
microsegundos (%D):
# Formato combinado avanzado incluyendo tiempo de proceso (%D) y cabeceras completas
LogFormat "%a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\" %D" combined_secure
CustomLog ${APACHE_LOG_DIR}/access.log combined_secure
# Nivel de detalle de errores: en producción se recomienda "warn" o "notice"
LogLevel warn
ErrorLog ${APACHE_LOG_DIR}/error.log1.13.2 Permisos seguros en el directorio de registros
Los registros nunca deben ser legibles por usuarios no privilegiados del sistema:
sudo chown -R root:adm /var/log/apache2
sudo chmod 750 /var/log/apache2
sudo chmod 640 /var/log/apache2/*.log1.13.3 Rotación segura con
logrotate
Verificamos la configuración de rotación en
/etc/logrotate.d/apache2 para evitar el agotamiento del
espacio en disco y garantizar la retención adecuada de evidencias para
auditorías:
/var/log/apache2/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 640 root adm
sharedscripts
postrotate
/usr/sbin/apache2ctl graceful > /dev/null
endscript
}
1.14 Auditoría de seguridad y herramientas de verificación
Una vez aplicadas las directivas de bastionado, es imprescindible auditar y validar la eficacia de las medidas adoptadas utilizando herramientas profesionales.
| Herramienta | Tipo | Objetivo principal |
|---|---|---|
| curl / httpie | Línea de comandos (CLI) | Inspección de cabeceras HTTP y códigos de respuesta. |
| testssl.sh | Script bash local (CLI) | Análisis exhaustivo de protocolos y suites TLS/SSL. |
| Nikto | Escáner de seguridad | Detección de ficheros sensibles y vulnerabilidades web. |
| Nmap NSE | Escáner de red | Auditoría de puertos abiertos y métodos HTTP admitidos. |
| Lynis | Auditoría de host | Evaluación integral del bastionado del SO y Apache. |
| SecurityHeaders.com | Servicio web online | Calificación y diagnóstico de cabeceras HTTP. |
| SSL Labs (Qualys) | Servicio web online | Calificación A+ de la configuración y certificados SSL. |
1.14.1 Verificación con
curl
# Inspeccionar cabeceras HTTP y validar ausencia de versiones
curl -I https://midominio.com
# Probar si el método TRACE está desactivado (debe devolver 403 o 405)
curl -X TRACE https://midominio.com
# Intentar acceder a un archivo sensible bloqueado (debe devolver 403 Forbidden)
curl -I https://midominio.com/.env
curl -I https://midominio.com/.git/config
curl -I https://midominio.com/backup.sql1.14.2 Auditoría criptográfica con
testssl.sh
testssl.sh es una herramienta de software libre que
evalúa cualquier servicio TLS para detectar cifrados obsoletos y
vulnerabilidades conocidas (Heartbleed, POODLE, ROBOT, DROWN,
CRIME):
# Descarga y ejecución de testssl
git clone --depth 1 https://github.com/drwetter/testssl.sh.git
./testssl.sh/testssl.sh https://midominio.com1.14.3 Escaneo de vulnerabilidades
web con Nikto
sudo apt install nikto -y
nikto -h https://midominio.com -ssl1.14.4 Auditoría completa del
sistema con Lynis
sudo apt install lynis -y
sudo lynis audit system1.15 Lista de verificación de bastionado
A continuación se resume la lista de verificación completa que todo administrador de sistemas debe validar antes del paso a producción:
| Nº | Medida de bastionado | Directiva / Comando clave | Archivo afectado |
|---|---|---|---|
| 1 | Actualización periódica del SO | apt update && apt upgrade -y |
Sistema operativo |
| 2 | Proceso bajo usuario sin privilegios | APACHE_RUN_USER=www-data |
/etc/apache2/envvars |
| 3 | Permisos restrictivos en DocumentRoot | Directorios 755, Ficheros
644, Propietario root:www-data |
/var/www/html |
| 4 | Bloqueo de ejecución en subidas (uploads) | <Directory "/uploads"> ForceType application/octet-stream ... |
conf-available/security.conf |
| 5 | Ocultar versión del servidor | ServerTokens Prod y
ServerSignature Off |
conf-available/security.conf |
| 6 | Ocultar cabeceras backend PHP | expose_php = Off /
Header always unset X-Powered-By |
php.ini /
security-headers.conf |
| 7 | Páginas de error personalizadas | ErrorDocument 404 /errores/404.html |
conf-available/security.conf |
| 8 | Denegación global por defecto | <Directory /> Require all denied </Directory> |
apache2.conf |
| 9 | Desactivar listado de directorios | Options -Indexes -FollowSymLinks +SymLinksIfOwnerMatch |
apache2.conf o
VirtualHost |
| 10 | Desactivar .htaccess
innecesarios |
AllowOverride None |
apache2.conf |
| 11 | Bloqueo de ficheros sensibles y ocultos | <FilesMatch "^\."> Require all denied </FilesMatch> |
conf-available/security.conf |
| 12 | VirtualHost catch-all / por defecto | 000-catchall.conf con
Require all denied |
sites-available/000-catchall.conf |
| 13 | Arquitectura moderna con
mpm_event |
a2enmod mpm_event proxy_fcgi
y php-fpm |
mods-enabled/ |
| 14 | Módulos mínimos e indispensables | a2dismod autoindex status info userdir cgi include dav |
mods-enabled/ |
| 15 | Desactivar método HTTP TRACE | TraceEnable Off |
conf-available/security.conf |
| 16 | Limitar métodos HTTP estándar | <LimitExcept GET POST HEAD OPTIONS> Require all denied |
apache2.conf o
VirtualHost |
| 17 | Cabeceras de seguridad HTTP | HSTS, CSP, X-Frame-Options, X-Content-Type-Options, etc. | conf-available/security-headers.conf |
| 18 | Cookies de sesión seguras | Header edit Set-Cookie ... "Secure; HttpOnly; SameSite=Lax" |
conf-available/security-headers.conf |
| 19 | Cifrado TLS 1.3 y TLS 1.2 moderno | SSLProtocol -all +TLSv1.2 +TLSv1.3 |
mods-available/ssl.conf |
| 20 | Grapado OCSP y HTTP/2 | SSLUseStapling on y
Protocols h2 http/1.1 |
ssl-stapling.conf /
VirtualHost |
| 21 | Mitigación DoS y Slowloris | mod_reqtimeout y reducción de
Timeout 30 |
apache2.conf /
reqtimeout.conf |
| 22 | Prevención de abusos y flood | mod_evasive con umbrales
realistas |
mods-available/evasive.conf |
| 23 | Cortafuegos WAF en capa 7 | ModSecurity con OWASP Core Rule Set
(SecRuleEngine On) |
/etc/modsecurity/ |
| 24 | Prevención de intrusiones con IPS | Fail2Ban con jaulas para Apache y WAF | /etc/fail2ban/jail.local |
| 25 | Registros enriquecidos y rotación | Formato combined_secure,
permisos 640, logrotate |
/var/log/apache2/ |
1.16 Actividades y ejercicios prácticos de laboratorio
A continuación se plantean siete actividades prácticas guiadas para afianzar los conocimientos en una máquina virtual de prácticas con Ubuntu Server.
1.16.1 Ejercicio 1: Auditoría inicial y ocultación de información
- Instala el servidor Apache en tu máquina virtual Ubuntu Server
(
sudo apt install apache2). - Realiza una petición con
curl -I http://localhosty anota la cabeceraServery las versiones visibles. - Modifica
/etc/apache2/conf-available/security.confpara establecerServerTokens ProdyServerSignature Off. - Habilita la configuración si no lo estuviera
(
sudo a2enconf security), comprueba la sintaxis conapache2ctl configtesty recarga el servicio. - Vuelve a ejecutar
curl -I http://localhosty comprueba que la versión exacta y la distribución han desaparecido.
1.16.2 Ejercicio 2: Restricción de permisos, bloqueo de ficheros y protección de subidas
- Crea en
/var/www/html/un archivo oculto llamado.envque contenga una clave simulada (DB_PASSWORD=secreto123) y un volcado de base de datosbackup.sql. - Crea un directorio
/var/www/html/uploads/y dentro de él crea un script de pruebainfo.phpque contenga<?php phpinfo(); ?>. - Comprueba con el navegador o
curlque inicialmente el servidor permite descargar.envy ejecutarinfo.php. - Añade a
/etc/apache2/conf-available/security.conflas reglas<FilesMatch>para bloquear archivos que comiencen por punto y extensiones sensibles (.sql,.bak,.env). - Añade la directiva de protección en
<Directory "/var/www/html/uploads">para denegar la ejecución de scripts PHP y forzarForceType application/octet-stream. - Recarga Apache y verifica con
curl -I http://localhost/.envycurl http://localhost/uploads/info.phpque en ambos casos se devuelve un código de estado403 Forbidden.
1.16.3 Ejercicio 3: Configuración del VirtualHost catch-all y redirección HTTPS
- Crea el archivo
/etc/apache2/sites-available/000-catchall.confcon una configuración que deniegue todo el tráfico a peticiones dirigidas por IP directa. - Habilita el sitio con
sudo a2ensite 000-catchall.conf. - Configura tu VirtualHost principal (por ejemplo
misitio.conf) conServerName misitio.local. - Comprueba que al acceder mediante
curl -H "Host: misitio.local" http://localhostse accede a la web, mientras que al acceder mediantecurl http://localhostse recibe un error403 Forbidden.
1.16.4 Ejercicio 4: Implementación y validación de cabeceras de seguridad y cookies
- Habilita el módulo de cabeceras
(
sudo a2enmod headers). - Crea el archivo
/etc/apache2/conf-available/security-headers.confe incluye las cabeceras recomendadas (X-Frame-Options,X-Content-Type-Options,Referrer-Policy,Permissions-Policy,Content-Security-Policy, cookie security). - Habilita la configuración
(
sudo a2enconf security-headers), valida conapache2ctl configtesty reinicia Apache. - Realiza una petición con
curl -I http://localhosty verifica que todas las cabeceras aparecen correctamente en la respuesta HTTP.
1.16.5 Ejercicio 5: Mitigación de
Slowloris y protección DoS con mod_reqtimeout y
mod_evasive
- Habilita el módulo
reqtimeout(sudo a2enmod reqtimeout). - Configura en
apache2.confunTimeoutde 30 segundos yKeepAliveTimeoutde 5 segundos. - Ajusta en
reqtimeout.conflos tiempos de lectura de cabeceras y cuerpo con tasa mínima de 500 bytes/s. - Instala y configura
libapache2-mod-evasivecon umbrales adecuados (DOSPageCount 10,DOSSiteCount 100). - Valida la sintaxis y reinicia el servicio.
1.16.6 Ejercicio 6: Despliegue de ModSecurity (WAF) y bloqueo de inyecciones SQL
Instala los paquetes
libapache2-mod-security2ymodsecurity-crs.Activa
SecRuleEngine Onen/etc/modsecurity/modsecurity.conf.Verifica la inclusión de las reglas OWASP en
/etc/apache2/mods-available/security2.confy reinicia Apache.Simula un ataque de inyección SQL enviando la siguiente petición:
curl "http://localhost/?id=1%20UNION%20SELECT%20null,username,password%20FROM%20users"Verifica que Apache responde con un error
403 Forbiddeny revisa la entrada generada en/var/log/apache2/modsec_audit.log.
1.16.7 Ejercicio 7: Detección y bloqueo activo con Fail2Ban
- Instala el paquete
fail2ban(sudo apt install fail2ban -y). - Crea
/etc/fail2ban/jail.localhabilitando las jaulasapache-auth,apache-badbots,apache-noscriptyapache-overflows. - Inicia el servicio Fail2ban y verifica su estado con
sudo fail2ban-client status. - Simula múltiples peticiones a scripts inexistentes
(
curl http://localhost/admin.php,curl http://localhost/setup.cgi, etc.) desde otra máquina o usando herramientas de prueba. - Comprueba con
sudo fail2ban-client status apache-noscriptque la IP atacante ha sido detectada y bloqueada en el cortafuegos.
2 Referencias
- Documentación oficial de Apache HTTP Server (Consejos de Seguridad)
- CIS Apache HTTP Server Benchmark
- NIST Special Publication 800-44: Guidelines on Securing Public Web Servers
- OWASP Web Server Security Cheat Sheet
- OWASP ModSecurity Core Rule Set (CRS)
- Mozilla SSL Configuration Generator
- Guía de Cabeceras de Seguridad HTTP de MDN Web Docs
- Herramienta de Auditoría testssl.sh
- Herramienta de Análisis Security Headers de Scott Helme
- Qualys SSL Labs Server Test
3 Licencia
Esta
página forma parte del curso
Implantación de Aplicaciones
Web de José Juan Sánchez
Hernández y su contenido se distribuye bajo una
licencia
Creative Commons Reconocimiento-NoComercial-CompartirIgual 4.0
Internacional.