Pasa tu web a HTTPS utilizando Let’s encrypt manual o automáticamente, tú decides

Publicado el 29 noviembre 2016 por Gaspar Fernández Moreno @gaspar_fm

La web no fue diseñada pensando en la seguridad, es decir, la comunicación se realiza de forma plana y cualquiera que pueda pinchar la línea puede ver los mensajes que pasan, el origen y el destino, y no hace falta ser un crack, sólo instalar un programa como Wireshark. Afortunadamente ahora tenemos HTTPS, es el mismo protocolo web, pero utilizando una capa de seguridad que cifra la comunicación entre las dos partes (nuestro navegador y el servidor) y hace que sea muy complicado que alguien que pueda interceptar la comunicación sepa qué estamos hablando.

La seguridad es muy importante hoy en día, ya que en casi todo tipo de páginas se intercambian datos sensibles, ya sean usuarios y contraseñas, direcciones de correo, datos personales, datos bancarios, o incluso datos que no queremos que sepa alguien (alguna foto comprometida, análisis clínicos, conversaciones, etc). Y actualmente, es muy cómodo transmitirlo todo sobre HTTP, ya que hacemos que un navegador sea capaz de tratar con los datos haciendo posible que muchos tipos de aplicaciones (móviles y de escritorio) puedan acceder fácilmente a la información. Antes se creaban aplicaciones específicas y protocolos propietarios cada vez que se trataba un tipo de información, y por supuesto, la seguridad había que programarla aparte. Ahora simplemente, los programadores incluyen una biblioteca de comunicación HTTP(s).

Google lleva tiempo amenazando con bajar el prestigio de webs sin HTTPS

Google empezó hace unos años penalizando un poco a páginas que no utilizaban HTTPS y pedían datos sensibles (tenían campos password, básicamente). Ahora mismo, las páginas que incluyen una capa de seguridad tienen premio en los posicionamientos. El problema es que HTTPS al mismo tiempo que cifra la comunicación, crea una verificación y da confianza al usuario dando validez al servidor al que accedemos diciendo que somos quien decimos ser. Por ejemplo, podemos hacer una página de phising con el aspecto de la página de un banco, pero el certificado no podrá nunca decir que somos ese banco (¿quién mira el certificado?). En este caso el navegador nos suele avisar, y no debemos aceptar los certificados a la ligera.
El tema, es que hasta el año pasado, tener un certificado para cifrar la conexión costaba dinero, un certificado que estuviera autorizado, claro. Es verdad que los hay muy baratos (4€/año), pero es un coste que si gestionas muchas webs se va multiplicando. Aunque también existen certificados que cuestan miles de euros, y todo tiene un motivo. Por supuesto, nos podíamos crear un certificado nosotros mismos, aunque todos los navegadores verían advertencias, porque nadie dice que nosotros seamos de confianza, y no hemos pagado por nuestra confianza.

Cuando pides un certificado, normalmente la empresa a la que lo pides realiza unas pruebas verificando quién eres, y que no haces cosas ilegales con tu sitio. Dependiendo del coste del certificado el examen puede ser más exhaustivo y tardar más. Los certificados más sencillos, sólo verifican tu IP, tu dominio y poco más. Los hay que te piden documentos de empresa para certificar quién eres, incluso identificación de empleados, responsables, documentos firmados que hay que remitir por correo y ellos guardarán bajo llave. Hay certificados como los EV (Extended Validation, validación extendida), que son los que solemos ver en los bancos, en los que la barra de direcciones aparece en verde y aparecen en el certificado más datos sobre el nombre de la organización, con el fin de dar confianza al usuario, ¡Eres quien dices ser!
Además, cuanta más verificación haya en ese certificado, mayor será la indemnización en caso de haber un problema. Dicha indemnización es al usuario afectado, por ejemplo, si han suplantado su identidad o le han robado información y es culpa del certificado o de que no se podía confiar en la empresa que han verificado (ellos no habrían hecho bien su trabajo diciendo que eres quien dices ser y que tienes un sitio legítimo). Esto no cubriría en principio fugas de información de la empresa.

También tenemos los certificados Wildcard que valen para cubrir un subdominio completo, por ejemplo todos los subdominios que haya bajo totaki.com (loquesea.totaki.com , privado.totaki.com , nube.totaki.com, etc) y suelen ser bastante caros aunque no tengan validación extendida. Pero suele ser más barato que comprar un certificado para cada uno de tus subdominios (si necesitas cierto nivel de confianza).

¿Qué diferencia hay entre Let's Encrypt y un certificado de pago?

Let's Encrypt es un certificado cuya intención es cifrar la comunicación. Por ejemplo si tienes un blog, o un pequeño sistema de usuarios y quieres que los datos se transmitan de forma segura, o dar un poco de confianza al usuario están muy bien. No son de validación extendida, ni lo pretenden, porque es un sistema automático sin intervención humana por parte de Let's Encrypt. Pero conseguimos una conexión cifrada, gratuita y Google no nos penaliza tanto (aunque puede que algún navegador o S.O. antiguo sí lo haga, pero no nos debería quitar el sueño). Eso sí, Let's Encrypt verifica que el dominio que estamos certificando corresponde con el servidor en el que estamos.

Los certificados de pago, normalmente nos dan algo de soporte técnico por chat, o por teléfono, y nuestros datos suelen ser archivados por un humano (no siempre, los de 4€ ni eso).

Si no tienes acceso SSH al servidor

Si no dispones de conexión SSH a tu servidor. Tendrás que decirle a tu proveedor de hospedaje que te instale el certificado para tu web. De todas formas, Let's encrypt está empezando a ser bastante famoso y muchos proveedores lo ofrecen de forma gratuita en sus paneles de control. Es cuestión de probarlo en tu web y con tu configuración actual, porque tal vez no haya ningún problema y lo puedas activar.

Eso sí, tienes que tener cuidado con la versión HTTP. Es interesante hacer que la versión HTTP redirija a HTTPS para que no haya contenidos duplicados, y sobre todo para que no haya ninguna cookie perdida que haga que un usuario identificado deje de estarlo al entrar en otra versión de la página. Debemos controlar dónde apuntan todos nuestros enlaces, pero muchas veces es casi imposible.

Instalación de certbot

Dependiendo de nuestra distribución, la instalación o el nombre del paquete varía. En muchos sitios lo veremos como certbot, en otros python-certbot, en otros se llama python-letsencrypt, por lo que podemos buscar el paquete por esos nombres. Por ejemplo en Debian 8, tenemos que buscar en los backports, añadiendo:

deb http://ftp.fr.debian.net/debian jessie-backports main
deb-src http://ftp.fr.debian.net/debian jessie-backports main

En /etc/apt/sources.list o en un archivo dentro de /etc/apt/sources.list.d/

Para ver la instalación detallada, podemos ir a esta página donde seleccionamos la distribución y el servidor web, porque aquí pondré un ejemplo directo para Apache sobre Debian Jessie (Debian 8):

Modo automático con certbot

Yo no soy muy fan de estos métodos automáticos que cambian cosas milagrosamente en el servidor. Creo que muchas veces estos sistemas tocan cosas que no deben y, aunque los buenos sistemas mantienen copias de lo archivos originales, nos suelen dar más de un susto. De hecho, Let's Encrypt me ha dado ya algún susto en un servidor que gestiono.

Pero claro, si acabas de instalarlo todo en el servidor, sólo tienes una web o no te importa que ocurra un susto y con ello problemas de downtime o de certificados en tu sitio, puedes probar este método.

o

Listo! Él ya se encarga. Nos hará ciertas preguntas e instalará el certificado donde corresponde. En teoría, aunque los ficheros de configuración los dejará un poco feos (sin anidados ni nada), además, aunque incluye configuraciones recomendadas para muchos escenarios, puede que machaque algunas configuraciones que ya tenemos.
En realidad certbot nos ahorra todo el tema de creación de claves, sign requests, envío a la autoridad para que lo firme, instalación de certificado y configuración de seguridad lo que muchas veces es de agradecer.

Pero la cosa no termina aquí, deberás mirar también el apartado de auto-renovación, ya que los certificados caducan a los 3 meses.

Certbot, con configuración manual

Para ello, tenemos que ejecutar certbot con los siguientes argumentos:

O si es la primera vez que lanzamos un certificado, tendremos que aceptar la licencia y dar una dirección de correo para incidencias, todo eso nos lo puede pedir de forma interactiva, pero si queremos automatizar el proceso no puede ser interactivo, por ello ejecutaremos lo siguiente:

Obtaining a new certificate

tls-sni-01 challenge for [dominio]

Waiting for verification...


Adicionalmente se pueden añadir dominios con todos los -d [dominio] que queramos. Dichos dominios serán VirtualHosts que tengamos hechos y se obtendrán a partir del ServerName. Por supuesto, los certificados pueden ser para un subdominio o un sub-sub dominio.

Con esto, hemos creado los certificados necesarios para correr el sitio web. Ahora, en Apache, debemos ir a nuestro virtualhost que se llamará por ejemplo certest.totaki.com y estará en el archivo /etc/apache2/sites-available/certest.totaki.com.conf (el archivo puede llamarse como quieras, pero me gusta poner nombres coherentes):


# The ServerName directive sets the request scheme, hostname and port that
# the server uses to identify itself. This is used when creating
# redirection URLs. In the context of virtual hosts, the ServerName
# specifies what hostname must appear in the request's Host: header to
# match this virtual host. For the default virtual host (this file) this
# value is not decisive as it is used as a last resort host regardless.
# However, you must set it for any further virtual host explicitly.
ServerName certest.totaki.com

ServerAdmin webmaster@localhost
DocumentRoot /var/www/html

# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the loglevel for particular
# modules, e.g.
#LogLevel info ssl:warn

ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined

# For most configuration files from conf-available/, which are
# enabled or disabled at a global level, it is possible to
# include a line for only one particular virtual host. For example the
# following line enables the CGI configuration for this host only
# after it has been globally disabled with "a2disconf".
#Include conf-available/serve-cgi-bin.conf
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Las últimas líneas de Rewrite son las que debemos añadir, haciendo que cuando alguien se conecte desde HTTP le redirija automáticamente a la versión HTTPS del sitio. Ahora bien, en otro fichero aparte dentro de /etc/apache2/sites-available/ (podemos llamarlo certest.totaki.com-ssl) o, si lo preferimos, podemos añadirlo en el mismo archivo: /etc/apache2/sites-available/certest.totaki.com debemos crear el virtualhost seguro, añadiendo lo siguiente:


# The ServerName directive sets the request scheme, hostname and port that
# the server uses to identify itself. This is used when creating
# redirection URLs. In the context of virtual hosts, the ServerName
# specifies what hostname must appear in the request's Host: header to
# match this virtual host. For the default virtual host (this file) this
# value is not decisive as it is used as a last resort host regardless.
# However, you must set it for any further virtual host explicitly.
ServerName certest.totaki.com

ServerAdmin webmaster@localhost
DocumentRoot /var/www/html

# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the loglevel for particular
# modules, e.g.
#LogLevel info ssl:warn

ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined

# For most configuration files from conf-available/, which are
# enabled or disabled at a global level, it is possible to
# include a line for only one particular virtual host. For example the
# following line enables the CGI configuration for this host only
# after it has been globally disabled with "a2disconf".
#Include conf-available/serve-cgi-bin.conf

# SSL Engine Switch:
# Enable/Disable SSL for this virtual host.
SSLEngine on

# Include certificate file and key
SSLCertificateFile /etc/letsencrypt/live/certest.totaki.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/certest.totaki.com/privkey.pem

# intermediate configuration, tweak to your needs
SSLProtocol all -SSLv3
SSLCipherSuite ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
SSLHonorCipherOrder on
SSLCompression off
SSLOptions +StrictRequire

Header always set Strict-Transport-Security "max-age=15768000"

Si ponemos la configuración del virtualhost seguro junto con la del inseguro será más fácil activar y desactivar webs con un sólo a2ensite/a2dissite. Es también una buena práctica, siempre que tengamos tiempo, verificar las nuevas configuraciones SSL gracias a Mozilla SSL Configuration Generator. Aquí tendremos muchas combinaciones de Servidores y versiones de software que nos ayudarán a mantener nuestro servidor seguro. Eso sí, cuanto más actualizado esté el servidor, mejores algoritmos de cifrado tendremos disponibles.

Auto renovación del certificado

Estos certificados duran unos tres meses. Y esto es bueno, normalmente los certificados pagados suelen durar un año, y cuando ocurren cosas como el bug Heartbleed, que nos obligó a renovar todos los certificados que teníamos, se nos fastidiaron todos los planes a los que trabajamos en seguridad. De hecho, puede suceder que haya vulnerabilidades no conocidas por los desarrolladores o por los administradores de sistemas que puedan ser explotados si nuestros certificados están demasiado tiempo sin cambiarse. Además, ya que han desarrollado un método automático para la renovación de estos certificados, ¿por qué no aprovecharlo?

Para ello tenemos que ejecutar el comando:

sudo certbot renew --dry-run

Incluso podemos poner un cron para que cada semana verifique esto, renovando todos los dominios que tengamos a punto de expirar (certbot considera por defecto que está a punto de expirar cuando faltan 10 días). Y si hemos tenido algún problema con esto, recibiremos un correo, adicionalmente, yo me envío también el resultado de esta tarea cron con MAILTO=:


Así editamos las tareas de root y añadimos:

# m h dom mon dow command
30 4 * * 1 certbot renew -dry-run

Para ejecutar todos los lunes a las 04:30 (suponemos que a esa hora no hay nadie que pueda ver un posible microcorte en el servicio).

Buenas prácticas

Aquí detallo algunas buenas prácticas que van surgiendo con los años y que considero interesantes.

Renovando certificados

Certbot permite la ejecución de scripts antes, durante y después de las renovaciones. Es decir, antes de pedir un certificado, podremos ejecutar un programa, tras cada renovación (imaginad que renovamos varios certificados) ejecutaremos otro programa y al final, ejecutaremos otro. Para ello, nos proporciona los siguientes modificadores:

Con esos scripts podemos hacer un log, enviar correos, establecer notificaciones o incluso recargar la configuración de servicios. Por ejemplo, cuando el certificado lo utilice también NodeJs o Nginx podemos hacer:


Aunque lo suyo es crear un pequeño script que cargue el servicio por si tenemos que ejecutarlo con un determinado usuario o ejecutarlo en una determinada ruta.

Configuración de SSL común

Algo que nos puede ayudar a la hora de mantener Apache es crear una configuración propia y común para todos los sitios alojados en el servidor. En lugar de modificar los ficheros de configuración de Apache, podemos crear una configuración propia en la que podemos incluir ajustes sobre SSL, seguridad y demás. Además, a la hora de llevarnos la configuración a otro servidor (o por si tenemos que hacer una actualización grande), no nos afectaría mucho, ya que ese fichero nadie lo va a tocar.

Para ello, debemos crear un fichero en /etc/apache2/conf-available/ y lo llamamos, por ejemplo, poesia.conf:


Require all denied
Require all denied
ServerToken Prod
ServerSignature Off
Header set X-Content-Type-Options: "nosniff"
Header set X-Frame-Options: "sameorigin"
Header set X-XSS-Protection "1; mode=block"
# OCSP Stapling, only in httpd 2.3.3 and later
SSLUseStapling on
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors off
SSLStaplingCache shmcb:/var/run/ocsp(128000)
# intermediate configuration, tweak to your needs
SSLProtocol all -SSLv3
SSLCipherSuite ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
SSLHonorCipherOrder on
SSLCompression off
Timeout 180
TraceEnable Off
FileETag MTime Size
#FileETag None

Y podemos incluir muchas cosas más. Por ejemplo, la configuración de protocolo SSL podemos incluirla en ese fichero y quitarla de los VirtualHosts. Además, podemos activar y desactivar con a2enconf/a2disconf.

Verificar datos de nuestro certificado

Está bien saber cómo está el certificado de vez en cuando, así que:

Nos va a dar mucha información útil.

Utilizar sólo recursos seguros

Todas las URLs que carguemos desde nuestra web deberán ser HTTPS, imágenes, scripts, estilos, tipos de letra, etc. Por eso tenemos que asegurarnos de ello. Y por eso es una mala idea meter las URLs a mano en el código de la web. Debemos tener en cuenta también los recursos que utilicemos desde CDN, por ejemplo jquery, y scripts por el estilo, cuya URL debería empezar ahora por https:// o simplemente por // (donde aprovechará el protocolo desde el que accedemos a la web principal).
El objetivo es evitar el candado naranja que nos indica que hay recursos no seguros. Además, aunque redirijamos a HTTPS todos los HTTP, no es plan de hacer que el navegador acceda a cada URL por HTTP y luego por HTTPS gracias a la redirección, porque tendríamos el doble de hits y estaríamos desperdiciando recursos de nuestro servidor.

Probar la seguridad de tu certificado

Es muy importante probar desde fuera que todo va bien, haciendo algo de auditoría a nuestra web. Para ello podemos utilizar los siguientes servicios:

Estos sitios suelen estar al día en cuanto a vulnerabilidades de cifrado y negociación y nos darán pistas de cómo hacer más segura la comunicación con nuestro servidor.

Más información

Instalando el certificado SSL en el blog, para instalarlo en nginx.
Let's Encrypt, certificados SSL libres y gratis para asegurar tu web con HTTPS, con consejos para utilizarlo en WordPress y cambiar tu web a HTTPs.
Foto: Matthew Henry

También podría interesarte...