Sitios seguros HTTPS con Let’s Encrypt
HTTPS o Hypertext Transfer Protocol Secure es un protocolo seguro de transferencia de hipertexto, es la versión segura de HTTP. Utiliza un cifrado basado en SSL/TLS para crear un canal seguro, ideal para transmitir información sensible como contraseñas. El puerto estándar es el 443.
Para habilitar HTTPS en un sitio web se requiere de un certificado, este puede ser generado por el administrador del sistema, sin embargo estos certificados son auto firmados, no hay una Autoridad Certificadora que los respalde, provocando que el navegador web despliegue una advertencia al usuario.
Let's Encrypt es una Autoridad Certificadora proveída por Internet Security Research Group (ISRG). Nace con el objetivo de simplificar el proceso de creación, validación, firmado, instalación y renovación de certificados. Entre sus características destaca que es gratuita, automatizada, segura, transparente, abierta y cooperativa. Su utilización es relativamente sencilla permitiendo obtener un certificado en unos pocos segundos.
Contenido
Configuración en Linux con Apache web server
Generación de los certificados
Let's Encrypt recomienda el script certbot, que permite automatizar el proceso. Este está disponible en certbot.eff.org
La recomendación es instalar a través de snap:
sudo snap install --classic certbot
Si desea consultar las opciones disponibles ejecute:
certbot --help all
Cree un archivo de configuración, de nombre configuracion.ini, utilizando un editor de texto, con el siguiente contenido (modifique según sea el caso):
# Usa una llave RSA de 4096 bits en lugar del predeterminado 2048
rsa-key-size = 4096
# Hace el registro con el correo-e especificado
email = micorreo@ucr.ac.cr
# Genera certificados para los dominios especificados
domains = sitio1.ucr.ac.cr, www.sitio1.ucr.ac.cr, sitio2.ucr.ac.cr
# Usar método de validación webroot
authenticator = webroot
webroot-path = /var/www/html/letsencrypt
El método de validación configurado requiere crear un directorio que Let's Encrypt accederá desde Internet para confirmar el o los dominios indicados.
Cree el directorio respectivo:
mkdir -p /var/www/html/letsencrypt
El script creará aquí el directorio oculto .well-known, para que sea accesible edite cada virtualhost de Apache para que tenga un alias que apunte ahí:
Por ejemplo, edite el archivo:
/etc/apache2/sites-enabled/sitio1.ucr.ac.cr
y añada las siguientes líneas:
# Autenticacion de letsencrypt usando webroot
Alias /.well-known /var/www/html/letsencrypt/.well-known
No olvide recargar la configuración:
service apache2 reload
Una vez hecho los preparativos, ejecute el script descargado con los siguientes parámetros:
certbot certonly -c configuracion.ini
El script valida el sitio y genera las respectivas llaves, para todos los dominios, en:
/etc/letsencrypt/live/sitio1.ucr.ac.cr/
Configuración del virtualhost
Se requieren lo siguientes módulos de apache:
- mod_ssl Soporte para utilizar SSL (HTTPS)
- mod_rewrite Permite reescribir URLs de acuerdo a reglas preestablecidas
- mod_headers Permite modificar los encabezados de las solicitudes y respuestas
Para ello se ejecuta:
a2enmod ssl rewrite headers
Algunas observaciones:
- El VirtualHost que respondía por el puerto 80 (http) ahora lo hará por el 443 (https)
- Cualquier solicitud con protocolo http se reescribirá como https
- Siempre se usa la llave del dominio principal (sitio1.ucr.ac.cr) aunque se estén configurandos otros dominios como sitio2.ucr.ac.cr
- Por seguridad se configura HTTP Strict Transport Security (HSTS)
Utilice un editor de texto para configurar cada virtualhost de la siguiente manera:
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName sitio1.ucr.ac.cr
# opcionalmente el www, según el caso
ServerAlias www.sitio1.ucr.ac.cr
DocumentRoot /var/html/www/sitio1
<Directory />
...
</Directory>
# Validación de letsencrypt usando webroot
Alias /.well-known /var/www/html/letsencrypt/.well-known
# Modulo SSL
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/sitio1.ucr.ac.cr/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/sitio1.ucr.ac.cr/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/sitio1.ucr.ac.cr/fullchain.pem
# Parche para Internet Explorer
BrowserMatch "MSIE [2-6]" \
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0
# MSIE 7 and newer should be able to use keepalive
BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
# Activa HSTS (Opcional - https://es.wikipedia.org/wiki/HTTP_Strict_Transport_Security)
# Header always set Strict-Transport-Security "max-age=63072000"
# no-www
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{SERVER_NAME} =www.sitio1.ucr.ac.cr
RewriteRule ^ https://sitio1.ucr.ac.cr%{REQUEST_URI} [NE,R=permanent]
</IfModule>
</VirtualHost>
</IfModule>
<VirtualHost *:80>
ServerName sitio1.ucr.ac.cr
# opcionalmente el www, según el caso
ServerAlias www.sitio1.ucr.ac.cr
# Siempre HTTPS, no-www
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{SERVER_NAME} =sitio1.ucr.ac.cr [OR]
RewriteCond %{SERVER_NAME} =www.sitio1.ucr.ac.cr
RewriteRule ^ https://sitio1.ucr.ac.cr%{REQUEST_URI} [NE,R=permanent]
</IfModule>
</VirtualHost>
Se recarga la nueva configuración:
service apache2 restart
Servidores con múltiples dominios
Con SSL el servidor no conoce el nombre de dominio solicitado hasta que no se establezca la conexión. Esto es un problema para un servidor con múltiples dominios (sitio1.ucr.ac.cr, sitio2.ucr.ac.cr, ...).
Se soluciona con una extensión de SSL llamada Server Name Indication (SNI), donde el cliente indica en el primer mensaje el nombre de dominio solicitado. Para ello se edita el archivo
/etc/apache2/ports.conf
y se añade la directiva:
<IfModule mod_ssl.c>
Listen 443
NameVirtualHost *:443
</IfModule>
Se reinicia el servicio tanto para recargar la nueva configuración como para habilitar los nuevos módulos:
service apache2 restart
Programar renovación automática de certificados
Los certificados expiran a los 90 días así que una buena recomendación es automatizar su renovación. Se puede ejecutar el script cada día o cada semana, si el certificado está pronto a expirar, este será renovado.
Si se desea programar semanalmente se crea el archivo:
/etc/cron.weekly/renew-ssl-certificates
con el siguiente contenido:
#!/bin/bash
certbot renew -c /ruta/a/configuracion.ini --post-hook "service apache2 reload"
Donde:
- renew indica que renueve certificados obtenidos previamente si estos están pronto a expirar
- -c CONFIG_FILE indica el archivo de configuración a usar
- --post-hook POST_HOOK indica un comando a ejecutar después de la renovación
Por último se le da permisos de ejecución
chmod +x /etc/cron.weekly/renew-ssl-certificates