Sitios seguros HTTPS con Let’s Encrypt

De Apuntes
Saltar a: navegación, buscar

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.

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