Seguridad de Servidores Linux/Windows: Una Guía Paso a Paso para Configuraciones Seguras
Rudra Chauhan, Senior Systems Architect
Seguridad de Servidores Linux/Windows: Una Guía Paso a Paso para Configuraciones Seguras
La seguridad de los servidores es un proceso continuo que comienza con una configuración de base sólida y evoluciona con inteligencia de amenazas. Esta guía te guía a través de la fortalecimiento de las superficies de ataque más críticas — SSH, TLS, firewalls y encabezados de seguridad HTTP — en ambas plataformas Linux y Windows, y luego une todo con un flujo de trabajo de mitigación de riesgos repetible.
Configuración del Servidor SSH - Mejores Prácticas para Conexiones Seguras
Respuesta directa: Fortalece sshd deshabilitando protocolos legados, imponiendo autenticación basada en claves, limitando el acceso y aplicando valores criptográficos sólidos por defecto.
Pasos de Fortalecimiento Básico (Linux)
bash# /etc/ssh/sshd_config – reemplaza el archivo completo o anexa estas líneas Puerto 2222 # puerto no estándar reduce escaneos automatizados Protocolo 2 PermitirLoginRaíz no Autenticación de Clave Pública sí Autenticación de Contraseña no Autenticación de Respuesta de Desafío no UsarPAM sí Métodos de Autenticación publickey PermitirUsuarios alice bob@192.0.2.0/24 # restrinja por usuario y CIDR de origen MaxIntentos 3 Tiempo de Gracia de Inicio de Sesión 20 Intervalo de Vida de la Sesión del Cliente 300 Número Máximo de Conteos de Vida de la Sesión del Cliente 2 Cifras chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com Algoritmos de Intercambio de Claves curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256 Algoritmos de Clave del Servidor ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com
Recarga: systemctl recargar sshd
Servidor OpenSSH de Windows (Win32-OpenSSH)
powershell# C:\ProgramData\ssh\sshd_config Puerto 2222 PermitirLoginRaíz no Autenticación de Clave Pública sí Autenticación de Contraseña no Métodos de Autenticación publickey PermitirUsuarios alice,bob MaxIntentos 3 Tiempo de Gracia de Inicio de Sesión 20 Intervalo de Vida de la Sesión del Cliente 300 Número Máximo de Conteos de Vida de la Sesión del Cliente 2 Cifras chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
Reinicia el servicio: Restart-Service sshd
Tabla de Referencia Rápida – Parámetros de Fortalecimiento de SSH
| Parámetro | Valor Recomendado | Razón |
|---|---|---|
Puerto | 2222 (o cualquier >1024) | Reduce el ruido de los escaneos de bots |
PermitirLoginRaíz | no | Evita el compromiso directo de la raíz |
Autenticación de Contraseña | no | Obliga la autenticación basada en claves |
Métodos de Autenticación | publickey | Garantiza el control de autenticación de MFA |
Cifras | chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com | Cifras AEAD modernas solo |
Algoritmos de Intercambio de Claves | curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256 | Intercambio de claves seguro hacia adelante |
PermitirUsuarios | alice bob@192.0.2.0/24 | Segmentación de red de privilegios más bajos |
Consejo del Hilo: Genera un archivo
sshd_configlisto para pegar con el Generador de Configuración SSH y valida la sintaxis mediantesshd -t.
Configuración SSL/TLS Segura – Implementación de Mejores Prácticas para la Encriptación
Respuesta directa: Implementa TLS 1.2 + 1.3 solo, utilice conjuntos de cifras sólidos, habilite HSTS, stapling de OCSP y certificado transparente.
Ejemplo de Nginx (Linux)
nginx# /etc/nginx/conf.d/ssl-hardening.conf servidor { escucha 443 ssl http2; nombre del servidor ejemplo.com; certificado ssl /etc/letsencrypt/live/ejemplo.com/fullchain.pem; clave de certificado ssl /etc/letsencrypt/live/ejemplo.com/privkey.pem; # Protocolo & Conjunto de Cifras ssl_protocols TLSv1.2 TLSv1.3; ssl_cifras 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256'; ssl_preferir_cifras_servidor off; # Stapling de OCSP ssl_stapling on; ssl_stapling_verificar on; resolutor 1.1.1.1 8.8.8.8 válido=300s; tiempo de espera de resolutor 5s; # HSTS (1 año, incluir subdominios, cargar previamente) agregar encabezado Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" siempre; # Encabezados de seguridad (consulte la sección siguiente) incluir /etc/nginx/security-headers.conf; }
PowerShell de IIS (Windows) – Fortalecimiento
powershell# Deshabilita TLS 1.0/1.1, habilite 1.2/1.3 Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server' -Name 'Enabled' -Value 0 Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server' -Name 'Enabled' -Value 0 Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server' -Name 'Enabled' -Value 1 Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Server' -Name 'Enabled' -Value 1 # Restringe conjuntos de cifras (ejemplo: solo AES-GCM & CHACHA20) $cifras = @( 'TLS_AES_256_GCM_SHA384', 'TLS_CHACHA20_POLY1305_SHA256', 'TLS_AES_128_GCM_SHA256' ) Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers' -Name 'Functions' -Value ($cifras -join ',') # Habilite HSTS a través de web.config (agrega a la raíz del sitio) <configuration> <system.webServer> <httpProtocol> <customHeaders> <add name="Strict-Transport-Security" value="max-age=31536000; includeSubDomains; preload" /> </customHeaders> </httpProtocol> </system.webServer> </configuration>
Referencia
- RFC 7519 de IETF – Token Web JSON (JWT) utilizado para autenticación sin estado; asegúrate de que los tokens se transmitan solo a través de canales protegidos por TLS.
Reglas de Firewall – Configuración de iptables, nftables, ufw y Windows Firewall para Acceso de Red Seguro
Respuesta directa: Adopta una postura de denegación por defecto, permite solo los puertos de entrada requeridos (SSH, HTTPS, gestión) y registra los paquetes rechazados para auditoría.
Linux – nftables (moderno, atómico)
bash#!/usr/sbin/nft -f limpia el conjunto de reglas tabla inet filtro { cadena de entrada { tipo filtro hook entrada prioridad 0; política denegación; iif "lo" aceptar ct estado establecido, relacionado aceptar # SSH (puerto personalizado) tcp dport 2222 ct estado nuevo límite 5/minute aceptar # HTTP/HTTPS tcp dport {80,443} aceptar # ICMP (límite de velocidad) icmp tipo echo-request límite 1/segundo aceptar # Registra y rechaza log prefijo "DROP_IN: " nivel info } cadena de forward { tipo filtro hook forward prioridad 0; política denegación; } cadena de salida { tipo filtro hook salida prioridad 0; política aceptar; } }
Linux – UFW (amigable con Ubuntu/Debian)
bashufw política denegación entrada ufw política aceptar salida ufw permitir 2222/tcp comentario 'Puerto SSH fortalecido' ufw permitir 80,443/tcp comentario 'Tráfico web' ufw límite 2222/tcp comentario 'Limita el acceso SSH' ufw habilitar
Windows Firewall – PowerShell (perfiles de dominio/privado)
powershell# Restablece a la configuración básica Set-NetFirewallProfile -Todos -DefaultInboundAction Block -DefaultOutboundAction Allow -NotifyDisplayEnabled False # Permite SSH (puerto personalizado) New-NetFirewallRule -DisplayName "Permite SSH 2222" -Dirección Entrante -Protocolo TCP -PuertoLocal 2222 -Acción Permitir -Perfil Dominio,Privado -Habilitado Verdadero # Permite HTTP/HTTPS New-NetFirewallRule -DisplayName "Permite HTTP/HTTPS" -Dirección Entrante -Protocolo TCP -PuertoLocal 80,443 -Acción Permitir -Perfil Dominio,Privado -Habilitado Verdadero # Habilite el registro de paquetes rechazados Set-NetFirewallProfile -Todos -LogFileName "%systemroot%\system32\LogFiles\Firewall\pfirewall.log" -LogMaxSizeKilobytes 4096 -LogAllowed False -LogBlocked True -LogIgnored True
Consejo del Hilo: Utiliza el Generador de Reglas de Firewall para producir los comandos exactos de
iptables,nftables,ufwo Windows Firewall para tu entorno.
Encabezados de Seguridad – Implementación de CSP, HSTS y Otros Encabezados Esenciales para Aplicaciones Web Seguras
Respuesta directa: Implementa un conjunto de encabezados de defensa en profundidad en cada respuesta HTTP: Content-Security-Policy, Strict-Transport-Security, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy y Cross-Origin-Opener-Policy.
Fragmento de Nginx (/etc/nginx/security-headers.conf)
nginx# Política de Seguridad de Contenido – ajusta las fuentes a tus activos agregar encabezado Content-Security-Policy "default-src 'self'; script-src 'self' 'nonce-$request_id' https://cdn.example.com; style-src 'self' 'nonce-$request_id' https://fonts.googleapis.com; img-src 'self' data: https://cdn.example.com; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self';" siempre; agregar encabezado Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" siempre; agregar encabezado X-Content-Type-Options "nosniff" siempre; agregar encabezado X-Frame-Options "DENY" siempre; agregar encabezado Referrer-Policy "strict-origin-when-cross-origin" siempre; agregar encabezado Permissions-Policy "geolocation=(), microphone=(), camera=()" siempre; agregar encabezado Cross-Origin-Opener-Policy "same-origin" siempre; agregar encabezado Cross-Origin-Resource-Policy "same-origin" siempre;
Apache (/etc/apache2/conf-available/security-headers.conf)
apacheEncabezado siempre establece Content-Security-Policy "default-src 'self'; script-src 'self' 'nonce-%{UNIQUE_ID}e' https://cdn.example.com; style-src 'self' 'nonce-%{UNIQUE_ID}e' https://fonts.googleapis.com; img-src 'self' data: https://cdn.example.com; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self';" Encabezado siempre establece Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" Encabezado siempre establece X-Content-Type-Options "nosniff" Encabezado siempre establece X-Frame-Options "DENY" Encabezado siempre establece Referrer-Policy "strict-origin-when-cross-origin" Encabezado siempre establece Permissions-Policy "geolocation=(), microphone=(), camera=()" Encabezado siempre establece Cross-Origin-Opener-Policy "same-origin" Encabezado siempre establece Cross-Origin-Resource-Policy "same-origin"
IIS – web.config (agrega debajo de <system.webServer>)
xml<httpProtocol> <customHeaders> <add name="Content-Security-Policy" value="default-src 'self'; script-src 'self' 'nonce-{RANDOM}' https://cdn.example.com; style-src 'self' 'nonce-{RANDOM}' https://fonts.googleapis.com; img-src 'self' data: https://cdn.example.com; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self';" /> <add name="Strict-Transport-Security" value="max-age=31536000; includeSubDomains; preload" /> <add name="X-Content-Type-Options" value="nosniff" /> <add name="X-Frame-Options" value="DENY" /> <add name="Referrer-Policy" value="strict-origin-when-cross-origin" /> <add name="Permissions-Policy" value="geolocation=(), microphone=(), camera=()" /> <add name="Cross-Origin-Opener-Policy" value="same-origin" /> <add name="Cross-Origin-Resource-Policy" value="same-origin"