Microordenadores - Desarrollos modernos para sistemas retro

Cómo instalar un certificado SSL para migrar un sitio web de HTTP a HTTPS
16 de Noviembre de 2016

¿Vas a migrar a HTTPS? asegúrate de no cometer errores y aprende a instalar el certificado SSL optimizando tu servidor para mejorar la accesibilidad y la velocidad de carga de tu web.

Configurar un certificado SSL en tu sitio web es conveniente en el caso de que pidas datos personales. Aquí aprenderás a instalar un certificado PositiveSSL en OpenBSD usando LibreSSL y httpd o nginx. El gran inconveniente de tener un sitio https es que se perderá compatibilidad con algunos dispositivos.

Medita bien la decisión de si adoptar o no https ya que, una vez migrado, volver atrás supone una serie de problemas. En mi opinión, HTTPS tiene sentido para sitios web donde se soliciten usuarios y contraseñas o datos sensibles como tarjetas de crédito. No veo la necesidad para sitios meramente informativos como éste, y el mayor problema es que una vez has migrado a https volver atrás es muy problemático ya que tendrás que mantener el certificado y una redirección 301 de la web https a la web http, y si has configurado hsts desactivarlo y esperar a que expire.

httpd es el servidor web que viene de serie en el sistema operativo OpenBSD, y se caracteriza por ser seguro, ligero y no padecer featuritis. Destacan las siguientes características:

  • Separación de privilegios: httpd corre bajo el usuario restringido www.
  • Chroot: El usuario www no puede salir del directorio /var/www/htdocs.
  • Configuración sencilla y fichero de configuración legible, al estilo de pf.conf.

Ventajas de un sitio HTTPS

  • Evita falsificaciones y la inyección de código.
  • Garantiza la confidencialidad, la autenticidad y la integridad de los datos, aunque hay que tener en cuenta la inseguridad de los navegadores y las resoluciones de DNS.
  • Obtener estadísticas más precisas, ya que sin SSL no se ven los referrers que vengan desde https.
  • Genera confianza (especialmente si usas certificados de Validación Extendida). Los sitios con certificado SSL correctamente instalado tienden a dar una sensación de confianza, especialmente importante en comercio online o si pedimos datos personales. Aquí tengo que decir que es muy criticable el sistema centralizado de emisión de certificados, y es peligroso dar la falsa sensación de seguridad de que al tener el candado se está seguro.
  • Es una forma de diferenciarse de los spammers, que trabajan con un gran volumen de dominios y para los que migrar a https supone un mayor esfuerzo. Google anunció que es una señal SEO, y es posible que en un tiempo los sitios web que no usen https bajarán posiciones en el buscador. Migrar a https, más que posicionar mejor, sirve para "vacunarse" y no perder posiciones por este motivo conforme la señal vaya cogiendo fuerza.
  • Evita que la web sea marcada como insegura con la pérdida de confianza que esto supone, especialmente a público no experto. En los navegadores Chrome y Firefox, los sitios http progresivamente serán marcados como inseguros.

Inconvenientes de un sitio HTTPS

  • Una vez que tu sitio funciona con https no hay marcha atrás, especialmente si usas hsts, que fuerza la conexión a los clientes que se han conectado al menos una vez durante el tiempo especificado, y además los nuevos links irán a la versión https.
  • La velocidad de carga puede sufrir, aunque se puede mejorar con algunas técnicas como usar SPDY, HTTP/2, OCSP Stapling y hsts preloading, enviando el dominio a incluir en la lista de preload para los principales navegadores.
  • Menor compatibilidad, con lo que dejaremos a usuarios fuera, lo cual rompe la web y el propósito original del HTML: mostrar contenido independientemente del dispositivo utilizado. Las versiones modernas de TLS no son compatibles con algunos agentes de usuario, aunque se puede mitigar configurando el servidor web para que acepte todas las versiones soportadas. Esto va contra el criterio de siempre devolver contenido útil, aunque no se vea bonito.
  • Necesitas una IP para cada sitio web con SSL, salvo que configures SNI, aunque esto da problemas de compatibilidad con algunos dispositivos.
  • Si no lo instalas correctamente puedes tener problemas con los buscadores. Debes asegurarte de que tu sitio sigue cargando rápido y que creas redirecciones 301 de la versión http a la versión https.
  • La carga de ficheros (como imágenes) desde una página https debe hacerse siempre a través de https, por lo que debes saber de antemano cómo funciona tu página para anticiparte a los posibles problemas.
  • Tu sitio no aparecerá en los referrers de las estadísticas de los sitios HTTP a los que enlaces.

Intercepción SSL

No todo es tan bonito como lo pintan. Existe la posibilidad de la intercepción SSL, de forma que cuando te conectas a un sitio aparece el candado verde aunque realmente estás conectado a un servidor intermedio que redirige la conexión. En este caso, la conexión segura es entre el navegador y un proxy y no directamente al servidor real al que te quieres conectar. No obstante, el fingerprint (huella) del certificado del sitio al que te conectas no puede ser falsificado.

Cómo comprobar que nuestra conexión SSL no está interceptada

Gracias al fingerprint puedes comprobar que tu conexión a un sitio determinado no está interceptada:

Sitio web Fingerprint SHA1
www.servidordesdecero.com CE:70:8E:02:EF:4D:5E:45:7B:5E:02:4F:C1:F2:B2:1B:BA:82:C1:FA
www.google.es A8:C9:BB:25:EC:D7:97:14:B3:F7:C4:8A:6D:4A:99:0B:A7:39:8A:55
www.freedns.zone BD:A5:E1:30:DF:93:0B:66:CF:D8:FE:77:39:40:D5:33:2E:54:57:7F

Si tu navegador ve un fingerprint distinto para esta página esto significa que tu conexión ha sido interceptada.

Qué certificado SSL instalar

Certificados SSL gratis

Let's Encrypt es una organización sin ánimo de lucro que provee de certificados de forma totalmente gratuita. Estos certificados funcionan de forma automatizada y abierta (todo el código de Let's Encrypt y las especificaciones del protocolo están en Github). Entre otras cosas, hay que tener en cuenta lo siguiente:

  • Actualmente estos certificados tienen problemas de compatibilidad con Windows XP y Java.
  • Necesitas un programa más ejecutándose en el servidor ya que los certificados expiran a los 90 días, y el cliente oficial no tiene fama de ser seguro, aunque a partir de OpenBSD 6.1 (y actualmente disponible en la rama current) se incluirá un cliente propio en el sistema base para usar estos certificados.
  • No soportan certificados de Validación Extendida ni wildcard.

Certificados SSL de pago

Actualmente uso PositiveSSL (proporcionado por Namecheap) que es barato (unos 8€ al año), funciona bien, no requiere ningún programa ejecutándose en nuestro servidor y cubre tanto el dominio desnudo como el dominio con www, a diferencia de RapidSSL que sólo sirve para un nombre de host con el problema que ello conlleva. Este último no lo recomiendo. Si quieres experimentar con la instalación, PositiveSSL te da la opción de obtener la devolución del dinero o incluso un certificado gratuito durante 30 días para probar antes de comprar.

Cómo instalar el certificado SSL

Al principio este tema parece muy lioso y complejo, luego es muy fácil, solo hay que seguir una serie de pasos:

  1. Generar la llave y el CSR.
  2. Solicitar un certificado al proveedor usando ese CSR.
  3. Empaquetar el certificado que nos llega al email e instalarlo junto a la llave.
  4. Configurar httpd o el servidor web que usemos.

Y lo mejor es que podemos hacer todo esto con las herramientas que trae de serie el sistema operativo OpenBSD: httpd y LibreSSL, con las ventajas que ello conlleva: foco en la seguridad y la simplificación, mucho menos trabajo de mantenimiento, configuración muy sencilla, excelente documentación y listas de correo, etc.

Dejo claro, al igual que en la página de portada, que este tutorial no sustituye leer la documentación y las páginas de manual, y aunque pretendo mantenerlo al día es posible que alguna configuración haya quedado anticuada cuando consultes esta página.

Cómo generar la llave y la petición de certificado (CSR)

$ openssl req -nodes -newkey rsa:2048 -sha256 -keyout server.key -out server.csr
Generating a 2048 bit RSA private key
............+++
.........+++
writing new private key to 'server.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) []: NL
State or Province Name (full name) []: Groningen
Locality Name (eg, city) []: Groningen
Organization Name (eg, company) []: BSDMOJO 
Organizational Unit Name (eg, section) []: BSDMOJO 
Common Name (eg, fully qualified host name) []:servidordesdecero.com
Email Address []:admin@servidordesdecero.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:

La contraseña la dejo vacía para que el servidor pueda reiniciar sin intervención (si vas a hacer esto, asegúrate de que es lo correcto). El archivo .key debemos protegerlo muy bien y nunca enviarlo en texto plano. Una vez hecho esto, pasamos al siguiente paso para obtener nuestro certificado.

Cómo obtener el certificado a partir del CSR

Simplemente compra un certificado COMODO PositiveSSL, por el precio de unos 8€/año. Te pedirá algunos datos y el archivo CSR que has generado anteriormente. A los pocos minutos te llegará un email para confirmar y una vez hecho esto te enviarán un archivo .zip que contiene dos archivos:

  • servidordesdecero.com.ca-bundle
  • servidordesdecero.com.crt

Como empaquetar e instalar el certificado

Esto es muy sencillo, en caso de usar otro proveedor o de tener dudas recomiendo contactar con dicho proveedor. En este caso tienes que agregar el contenido del archivo bundle al certificado .crt. Yo lo hago así:

$ cp servidordesdecero.com.crt server.crt
$ cat servidordesdecero.com.ca-bundle >> server.crt

Y ya tenemos el par de archivos necesarios para que nuestro certificado funcione correctamente. Simplemente movemos este archivo server.crt al directorio /etc/ssl y el server.key que generamos inicialmente a /etc/ssl/private. Este server.key debe ser solamente escribible y legible para el propietario (-rw——-) y pertenecer a root:wheel.

A día de hoy, tal y como proporciona COMODO PositiveSSL su archivo bundle, el último bloque corresponde al root anchor. Aunque no es incorrecto, aumentará el tiempo de conexión y no es necesario, por lo que puedes eliminarlo.

Configuración de httpd

Primero de todo lee httpd.conf(5). La configuración que uso no puedo asegurar que sea correcta por lo que NO recomiendo copiar-pegar sin saber lo que hace cada parámetro.

Con la opción hsts es posible forzar la conexión segura. Hay que tener en cuenta que una vez que se activa el hsts se forzará el https y aunque lo quitemos, quienes nos hayan visitado (también Googlebot) intentarán cargar la versión https durante el tiempo especificado en el parámetro max-age. Por otra parte ofrece una mejora de rendimiento ya que cuando alguien se vuelve a conectar su navegador lo enviará directamente a la versión https. Para hacer pruebas y poder volver a la versión no-ssl es conveniente no usar esta opción.

Ten en cuenta que si tienes la opción hsts activada sólo podrás usar los nombres de hosts que permita tu certificado, es decir, tudominio.com y www.tudominio.com si usas PositiveSSL, pero no foo.tudominio.com, salvo que pagues por un certificado wildcard.

Si ves errores en /var/log/daemon relativos al server.key debes asegurarnos que el archivo está en formato PEM y que el server.crt es correcto. En este caso lo mejor es contactar al proveedor del servicio SSL (en caso de que no uses un certificado firmado por tí mismo).

Recomendación: nunca actives hsts hasta comprobar que todo funciona correctamente. Asegúrate de que las suites de cifrado indicadas son seguras antes de instalarlas, y lee la documentación oficial.

server "www.example.com" {
        listen on * tls port 443
        listen on :: tls port 443 
        tls ciphers ""  # Check https://wiki.mozilla.org/Security/Server_Side_TLS 
        tls protocols all             # TLSv1.0, TLSv1.1 and TLSv1.2 for compatibility 
        hsts max-age 15552000         # Tell the browsers to always connect over https 
        hsts preload         # Site permitted to be included in preload list
        hsts subdomains    # This hosts and all subdomains are HSTS hosts
        root "/var/www/htdocs/example.com"
        log access example-access.log
        log error example-error.log
        log style combined
}

server "www.example.com" {
        listen on * port 80
        listen on :: port 80
        block return 301 "https://$SERVER_NAME$REQUEST_URI"
}

server "example.com" {
        listen on * tls port 443
        listen on :: tls port 443
        tls ciphers "" # check https://wiki.mozilla.org/Security/Server_Side_TLS
        tls protocols all             # TLSv1.0, TLSv1.1 and TLSv1.2 for compatibility 
        hsts max-age 15552000         # Tell the browsers to always connect over https 
        hsts preload         # Site permitted to be included in preload list
        hsts subdomains    # This hosts and all subdomains are HSTS hosts
        root "/var/www/htdocs/example.com"
        block return 301 "https://$SERVER_NAME$REQUEST_URI"
}

server "example.com" {
        listen on * port 80
        listen on :: port 80
        block return 301 "https://$SERVER_NAME$REQUEST_URI"
}

La línea tls ciphers especifica una configuración que es una solución de compromiso entre seguridad y compatibilidad; con tls protocols all, por compatibilidad, aceptamos conexiones TLSv1.0, TLSv1.1 y TLSv1.2, dejando aparte SSLv3 que ya no es soportado en LibreSSL. Con la opción hsts max-age 15552000 le decimos a los navegadores que nos visiten que durante ese intervalo de tiempo en segundos (tres meses) se conecten directamente a la versión https. Otra opción que uso y que parece dar buen resultado para la negociación SSL es tcp_nodelay.

Recomiendo encarecidamente investigar antes de usar esta configuración, ya que no estoy del todo seguro de que sea correcta (aunque SSLLabs me da puntuación de A+); imprescindible leer la sección CIPHERS de openssl(1). Una vez configurado y añadido httpd_flags= a /etc/rc.conf.local arrancamos httpd:

$ doas /etc/rc.d/httpd start

Comprobando la configuración

Entramos en nuestra página y veremos el famoso candadito desde Firefox o Chromium. La configuración por defecto de httpd es segura y no debemos preocuparnos de especificar una serie de parámetros como ocurre con nginx.

Pinchando el candadito en chromium veremos una información de este tipo: Tu conexión con www.servidordesdecero.com está cifrada con un conjunto de cifrado moderno. La conexión usa TLS 1.2. La conexión se ha encriptado y autenticado con CHACHA20_POLY1305, y utiliza ECDHE_RSA como el mecanismo de intercambio de clave.

Para finalizar comprueba tu sitio en SSL Labs para comprobar que la puntuación es de A+.

Asegúrate de elegir una suite de cifrado que sea una solución de compromiso entre accesibilidad y seguridad, de optimizarlo bien y leer la documentación antes de la implementación. En httpd, características como compresión y SPDY han sido desechadas por ser una potencial fuente de problemas (al menos de momento). En el caso de SPDY esto se confirmó más tarde cuando aparecieron fallos de seguridad en la implementación de Nginx.

HTTPS en nginx

Aunque httpd es fantástico y funciona muy bien, es posible que busques algunas prestaciones de Nginx. Por suerte, OpenBSD no te impide instalar nginx desde el sistema de paquetes, incluso lo facilita instalándolo por defecto con chroot y separación de privilegios.

La suite de cifrado que da A+ y mayor compatibilidad para nginx que he encontrado es la intermedia de Server Side TLS en Mozilla, aunque no recomiendo usarla a ciegas, asegúrate de que a día de hoy no sea insegura. Si usas sistemas operativos BSD, en nginx no te olvides de especificar kqueue en la sección events, mientras que si usas Linux la opción es epoll. Para configurar OCSP Stapling, y de acuerdo a lo que me han dicho en Namecheap, se usa el fichero bundle con o sin el certificado root, que es el último bloque.

Configuración optimizada

Antes de nada hago una advertencia: no copies y uses esta configuración sin estudiarla leyendo la documentación oficial, y asegurándote de que no haya ningún error. Es la configuración experimental que he hecho para comprobar el rendimiento, y es posible que no sea del todo correcta o que cuando estés leyendo esto la suite de cifrado elegida sea obsoleta. He configurado las siguientes prestaciones:

  • OCSP Stapling. Reduce el tiempo que tarda el handshake SSL guardando en caché la información del certificado SSL.
  • Session caching. Guarda en cache los parámetros de la conexión SSL.
  • Session tickets. Guarda información sobre sesiones SSL evitando nuevos handshakes.
  • HTTP/2 da problemas de compatibilidad con algunos navegadores, como Firefox 45.2.0.
  • HSTS. Guarda información en el navegador haciendo que a partir de la segunda vez fuerce conexión https.
  • Compresión gzip. Ahorra ancho de banda.
  • Suite de cifrado con la máxima compatibilidad que puntúa con A+ en SSLLabs.

El fichero dhparam.pem se genera de la siguiente forma:

$ openssl dhparam 2048 -out /etc/nginx/dhparam.pem
nginx.conf

No olvides leer http://wiki.nginx.org/Pitfalls y añadir la suite de cifrado indicada en la página de Mozilla sobre TLS de lado del servidor. Aquí uso la suite intermedia para no perder compatibilidad con muchos dispositivos.

# Take note of http://wiki.nginx.org/Pitfalls

#user  www;
worker_processes  1;

error_log  logs/nginx-error.log;

#pid        logs/nginx.pid;

worker_rlimit_nofile 1024;
events {
    worker_connections  800;
    multi_accept        on;
    use                 kqueue;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    index         index.html index.htm;

    #access_log  logs/access.log  main;
    #access_log  syslog:server=unix:/dev/log,severity=notice main;

    #sendfile       on;
    #tcp_nopush     on;
    #tcp_nodelay    on;  # mirar la documentación, según cada caso se
												 # activan unos u otros.

    #keepalive_timeout  0;
    keepalive_timeout  65;

    gzip        on;
    gzip_disable "msie6";
    gzip_comp_level 6;
    gzip_min_length 1100;
    gzip_buffers 16 8k;
    gzip_proxied any;
    gzip_types text/plain text/css text/javascript image/x-icon;
    server_tokens off;

    server {
        listen       80;
        listen       [::]:80;
        server_name  87.238.175.189;
				return 301	 https://www.servidordesdecero.com;  # Dedicated IP 
    }

    server {             # http://servidordesdecero.com -> https://servidordesdecero.com
        listen       80;
        listen       [::]:80;
        server_name  servidordesdecero.com;
        return 301   https://servidordesdecero.com;
    }

    server {             # http://www.servidordesdecero.com -> https://www.servidordesdecero.com
        listen       80;
        listen       [::]:80;
        server_name  www.servidordesdecero.com;
        return 301   https://www.servidordesdecero.com;
    }

    server {             # https://servidordesdecero.com -> https://www.servidordesdecero.com
        listen       443 ssl;
        listen       [::]:443 ssl;
        server_name  servidordesdecero.com;
        ssl_certificate /etc/ssl/server.crt;
        ssl_certificate_key /etc/ssl/private/server.key;
        ssl_session_cache shared:SSL:20m;
        ssl_session_timeout 4h;
				ssl_session_tickets on;
        ssl_prefer_server_ciphers on;
        ssl_ciphers ;  # Check https://wiki.mozilla.org/Security/Server_Side_TLS for "Intermediate ciphers"
        ssl_dhparam /etc/nginx/dhparam.pem;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_stapling on;
        ssl_stapling_verify on;
        ssl_trusted_certificate /etc/ssl/server-ocsp.crt;
        resolver 8.8.8.8 8.8.4.4 valid=300s;
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
        return 301   https://www.servidordesdecero.com;
    }

    server {        # https://www.servidordesdecero.com
        listen       443 ssl;
        listen       [::]:443 ssl;
        server_name  www.servidordesdecero.com;
        ssl_certificate /etc/ssl/server.crt;
        ssl_certificate_key /etc/ssl/private/server.key;
        ssl_session_cache shared:SSL:20m;
        ssl_session_timeout 4h;
				ssl_session_tickets on;
        ssl_prefer_server_ciphers on;
        ssl_ciphers ; # check https://wiki.mozilla.org/Security/Server_Side_TLS for "Intermediate ciphers" 
        ssl_dhparam /etc/nginx/dhparam.pem;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_stapling on;
        ssl_stapling_verify on;
        ssl_trusted_certificate /etc/ssl/server-ocsp.crt;
        resolver 8.8.8.8 8.8.4.4 valid=300s;
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
        root         /var/www/htdocs/servidordesdecero.com;
        error_page   404 /error404/;
        access_log   logs/servidordesdecero-access-ng.log;
        error_log    logs/servidordesdecero-error-ng.log;
    }
}

Enlaces


Contenido relacionado: