HTTPS y Seguridad de Transporte
HTTPS encripta los datos en tránsito entre cliente y servidor, previniendo espionaje y manipulación. Ya no es opcional—es requerido para cualquier aplicación web moderna.
Por Qué Importa HTTPS
- Encriptación - Los datos no pueden ser leídos por atacantes
- Integridad - Los datos no pueden ser modificados en tránsito
- Autenticación - Los usuarios saben que están en el sitio real
- SEO - Google posiciona mejor sitios HTTPS
- Características - Requerido para HTTP/2, service workers, etc.
Configurando HTTPS con Let's Encrypt
# Usando Certbot para gestión automática de certificados
sudo apt install certbot python3-certbot-nginx
# Obtener certificado
sudo certbot --nginx -d example.com -d www.example.com
# Auto-renovación se configura automáticamente
# Probar con:
sudo certbot renew --dry-run
Servidor HTTPS en Node.js
const https = require('https');
const fs = require('fs');
const express = require('express');
const app = express();
const options = {
key: fs.readFileSync('/path/to/privkey.pem'),
cert: fs.readFileSync('/path/to/fullchain.pem'),
// Configuración TLS moderna
minVersion: 'TLSv1.2',
ciphers: [
'ECDHE-ECDSA-AES128-GCM-SHA256',
'ECDHE-RSA-AES128-GCM-SHA256',
'ECDHE-ECDSA-AES256-GCM-SHA384',
'ECDHE-RSA-AES256-GCM-SHA384',
].join(':'),
};
https.createServer(options, app).listen(443);
// Redireccionar HTTP a HTTPS
const http = require('http');
http.createServer((req, res) => {
res.writeHead(301, { Location: `https://${req.headers.host}${req.url}` });
res.end();
}).listen(80);
HSTS (HTTP Strict Transport Security)
// Forzar HTTPS para todas las solicitudes futuras
app.use((req, res, next) => {
res.setHeader(
'Strict-Transport-Security',
'max-age=31536000; includeSubDomains; preload'
);
next();
});
// O con Helmet
const helmet = require('helmet');
app.use(helmet.hsts({
maxAge: 31536000, // 1 año
includeSubDomains: true, // Aplicar a todos los subdominios
preload: true, // Permitir precarga HSTS
}));
Configuración HTTPS en Next.js
// next.config.js
module.exports = {
async headers() {
return [
{
source: '/:path*',
headers: [
{
key: 'Strict-Transport-Security',
value: 'max-age=31536000; includeSubDomains; preload',
},
],
},
];
},
// Forzar HTTPS en producción
async redirects() {
return process.env.NODE_ENV === 'production'
? [
{
source: '/:path*',
has: [{ type: 'header', key: 'x-forwarded-proto', value: 'http' }],
destination: 'https://example.com/:path*',
permanent: true,
},
]
: [];
},
};
Certificate Pinning
// Fijación de Clave Pública (para apps móviles o aplicaciones críticas)
const https = require('https');
const crypto = require('crypto');
const expectedFingerprint = 'SHA256:XXXX...';
const options = {
hostname: 'api.example.com',
port: 443,
checkServerIdentity: (host, cert) => {
const fingerprint = crypto
.createHash('sha256')
.update(cert.raw)
.digest('base64');
if (`SHA256:${fingerprint}` !== expectedFingerprint) {
throw new Error('¡Huella del certificado no coincide!');
}
},
};
https.get(options, (res) => {
// Proceder con la solicitud
});
Configuración HTTPS en Nginx
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com www.example.com;
# Archivos de certificado
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Configuración TLS moderna
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;
ssl_prefer_server_ciphers off;
# HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
# Configuración de sesión
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
}
Probando Configuración TLS
# Probar con SSL Labs
# Visita: https://www.ssllabs.com/ssltest/
# Probar con OpenSSL
openssl s_client -connect example.com:443 -servername example.com
# Verificar expiración del certificado
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates
# Probar versión específica de TLS
openssl s_client -connect example.com:443 -tls1_2
openssl s_client -connect example.com:443 -tls1_3
Problemas de Contenido Mixto
<!-- MAL: Cargar recursos HTTP en página HTTPS -->
<img src="http://example.com/image.jpg">
<script src="http://cdn.example.com/script.js"></script>
<!-- BIEN: Usar HTTPS o URLs relativas al protocolo -->
<img src="https://example.com/image.jpg">
<img src="//example.com/image.jpg">
<!-- Mejor: Usar CSP para bloquear contenido mixto -->
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
Lista de Verificación HTTPS
- Usa solo TLS 1.2 o 1.3 (deshabilita versiones antiguas)
- Usa suites de cifrado fuertes
- Habilita HSTS con max-age largo
- Redirige todo HTTP a HTTPS
- Usa cookies seguras (flag Secure)
- Arregla problemas de contenido mixto
- Configura renovación automática de certificados
- Habilita OCSP stapling
- Prueba con SSL Labs (apunta a calificación A+)