Autenticación mutua de cliente y servidor con certificados

Publicado por pico.dev el , actualizado el .
blog-stack java planeta-codigo planeta-linux programacion seguridad
Comentarios

OpenSSL

Los certificados no solo sirven para autenticar a un servidor o acceder solo a aquellos en los que confiamos. El servidor también puede autenticar a los clientes mediante un certificado como alternativa a usar un usuario y contraseña ya sea una autenticación BASIC o un formulario personalizado. Al igual que en el cliente usa el certificado de la autoridad de certificación en la que confía para validar el que presenta el servidor, el servidor puede requerir que el cliente también proporcione un certificado que el servidor valida según las autoridades de certificación en las que confía, en ambos casos el servidor o cliente usan su clave privada para iniciar la conexión segura con el handsake del protocolo TLS.

Para el ejemplo usaré un servidor web nginx ejecutado como un contenedor de Docker configurado de tal manera que requiere autenticación para el cliente con certificados.

Inicialmente deberemos generar tres parejas de claves privadas y públicas, una para nuestra propia autoridad de certificación, una clave para el servidor y otra para el cliente. Al mismo tiempo generaré otras tres parejas de claves privadas y públicas para comprobar que cuando se proporciona un certificado incorrecto la autenticación falla.

El siguiente paso es generar los certificados y firmar con la clave y certificado de la autoridad de certificado los certificados del servidor y cliente. Como paso previo a que la autoridad de certificación emita los certificados del servidor y cliente hay que generar una petición de firma de certificado, los archivos .csr.

Con la misma herramienta de OpenSSL es posible comprobar si un certificado es válido para una autoridad de certificación en la que se confía, para ello se usa el certificado raiz de la autoridad.

Para hacer que el servidor nginx requiera autenticación mediante certificados para el cliente hay que añadir un poco de configuración mediante las directivas ssl donde se indica el certificado del servidor, la clave privada del servidor, el certificado de la autoridad de certificación contra la que se validarán los certificados de los clientes y finalmente la directiva que establece que se ha de verificar a los clientes mediante certificados.

Con el siguiente archivo descriptor de Docker Compose y comando se inicia el servidor web nginx.

Iniciado el servidor web ya se pueden realizar peticiones y el servidor y el cliente se autenticarán mutuamente. El servidor devolverá el código HTML de la página de bienvenida por defecto con las cabeceras del protocolo HTTP después de realizar el handsake donde se valida el certificado del servidor.

Si se intenta realizar una petición sin certificado de cliente o con un certificado de cliente en el que no confié el servidor (que no esté firmado por la autoridad de certificación en la que confía) se devolverá un código de estado 400 que indica que la petición se ha rechazado. También el cliente advertirá si la autoridad de certificación en la que confía no valida el certificado del servidor con un error 400 y título 400 The SSL certificate error.

El siguiente script escrito en lenguaje Groovy muestra como desde un programa para la plataforma Java se realiza autenticación mutua y que error da cuando alguno de los certificados es inválido ya sea el del cliente o el del servidor. Generando previamente los keystores de la autoridad de certificado y del cliente introduciendo como clave en el ejemplo password cuando se solicita.

En caso de que al usar un keystore con un certificado de una autoridad que no valida el certificado del servidor se producirán un error, también cuando el certificado del cliente no sea válido para el servidor.

Lo anterior es usando la herramienta curl o un un programa en la plataforma Java, en el caso de querer realizar autenticación mutua con un navegador web como Firefox hay que instalar el certificado del cliente y si es necesario el certificado de la autoridad de certificación para que el candado indicativo de la seguridad del protocolo HTTPS se muestre en verde y no indique ningún problema de seguridad en la autenticación del servidor. En Firefox los certificados se añaden en el menú Preferencias > Avanzado > Ver certficados. En la pestaña Sus certificados hay que importar el certificado del cliente en formato PKCS12 y en la pestaña Autoridades el certificado de la autoridad que haya firmado el certificado del servidor, con el botón Importar se selecciona el archivo crt de la autoridad. Al introducir la URL y realizar la petición Firefox solicita mediante un diálogo seleccionar el certificado a usar para realizar la autenticación en el servidor.

Autenticación mutua de cliente y servidor con el navegador web Firefox

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando el comando docker-compose up && groovy MutualCertAuth.groovy.