Configurar el servidor web (en aquest cas Apache) per a que validi certificats de confiança (en aquest cas del DNIe) és una tasca important en les mesures de seguretat i autenticació de l'administració pública, i pot esdevenir-ho també en un futur per a la gestió privada. L'administració pública necessita uns estàndards molt alts de seguretat, sobretot en el què respecta a autenticació i validació de la identitat de l'usuari.
En realitat el que realitzarem serà una autenticació mútua entre servidor i client, essent necessaris tant a l'un com a l'altre la configuració dels certificats de la CA (Certificate Authority, pel nostre cas el «AC RAIZ DNIE 2») i, per part del client, el certificat signat per aquesta mateixa CA (present dins del DNIe).
Referències i ampliacions:
Primer de tot caldrà que tingueu el DNIe amb els certificats vàlids. Per solventar-ho cal que aneu a una Commissaria de la Policía Nacional i us assegureu que renoveu els certificats i coneixeu el vostre PIN.
És molt important tenir el PIN clar perquè les smart cards es bloquegen als 3 errors d'accés. Si es donessin aquests 3 accessos erronis caldria tornar a la Comissaria per renovar els certificats.
Necessitarem un lector de targetes que funcioni amb el DNIe. Aquest lector de targetes de Zoweetek, per exemple, sabem que és compatible amb el DNIe tant per a GNU/Linux com per a Windows i Mac.
Pot ser que el lector de smart cards no estigui habilitat. Per comprovar-ho en GNU/Linux podem fer:
$ pcsc_scan
Si el servei no està instal·lat, es pot fer amb:
$ sudo apt install pcsc-tools pcscd
Si continua sense funcionar pcsc_scan
, es pot activar amb:
$ sudo systemctl enable pcscd $ sudo systemctl start pcscd $ pcsc_scan
Per a Windows l'executable descarregat a la web del DNIe realitza aquestes passes més o menys automàticament si no hi ha cap error.
Àrea de descàrregues a la pàgina oficial del DNIe per als diferents SO.
A la pàgina de descàrregues del DNIe es mostra el paquet DEB per a versions fins la Ubuntu 21.10, però no la darrera Ubuntu 22.04 LTS. El problema, segons aquest post, és la versió snap (enlloc de la clàssica APT) de Firefox que Canonical fa servir des d'aquesta versió.
Per solventar-ho, podem desinstal·lar Firefox i instal·lar la versió Firefox ESR (Extended Support Release) més estable i que actualment és un estàndard d'estabilitat en distribucions com Debian.
Desinstal·lem el Firefox de snap (pot trigar una mica, mira de tancar totes les pantalles de Firefox primer):
# snap remove firefox
Afegim els repositoris de mozillateam i instal·lem firefox-esr:
# apt install software-properties-common -y # add-apt-repository ppa:mozillateam/ppa # apt install firefox-esr
Si es paralitza la instal·lació, tanca la finestra de Firefox que s'ha obert. Ens obriria un breu tutorial d'instal·lació dels certificats del DNIe, però de vegades no apareix i ja l'he copiat aquí a la següent secció.
Afegim un enllaç simbòlic per facilitar la comanda firefox
:
# ln -s /usr/bin/firefox-esr /usr/bin/firefox
Ara ja podem seguir i instal·lar el package DEB de la web oficial del DNIe.
Caldrà que tinguem la màquina client i el navegador configurats adientment per poder utilitzar el DNIe:
Àrea de descàrregues a la pàgina oficial del DNIe per als diferents SO.
Bàsicament la instal·lació té aquestes passes:
sudo dpkg -i arxiu.deb sudo apt install -f
Firefox > Paràmetres > Privadesa i seguretat > Certificats > Dispositius > Carrega /usr/lib/libpkcs11-dnie.so
Si et surt l'error:
No s'ha pogut afegir el mòdul
Ves a la secció anterior de «Resolució amb Ubuntu 22.04» per solucionar-ho.
Firefox > Paràmetres > Privadesa i seguretat > Certificats > Mostra els certificats
/usr/share/libpkcs11-dnie/AC RAIZ DNIE 2.crt
Per acabar de comprovar que el client funciona correctament, proveu verificar-ho a:
Podem fer la pràctica en un servidor públic (Cloud) però també funciona en un servidor local (VM).
Podem fer una instal·lació en local, és la manera més senzilla.
Encara que els certificats del HTTPS siguin autofirmats, podem realitzar l'autenticació de client requerint el DNIE.
També és recomanable (no imprescindible) engegar una màquina Vagrant per aïllar la instal·lació i no enredar les configuracions de la màquina host. Crea el següent Vagrantfile
en una carpeta per a la teva VM:
# -*- mode: ruby -*- # vi: set ft=ruby : Vagrant.configure("2") do |config| config.vm.box = "ubuntu/jammy64" config.vm.hostname = "ubudnie" config.vm.network "private_network", ip: "192.168.33.10" config.vm.provider "virtualbox" do |vb| vb.name = "ubudnie" vb.gui = false vb.memory = "2048" end end
Entrem a la VM amb:
$ vagrant ssh
Fem instal·lació bàsica d'Apache i PHP i activem SSL:
default-ssl.conf
La pràctica es pot muntar perfectament en la màquina local. Tot i això, perquè sigui operativa de veritat ha d'estar en un servidor públic i amb certificats vàlids.
Així, recomanem aquestes passes:
Si arribes aquí, ja tenim el server preparat per activar autenticació via DNIe al teu site.
Si estàs fent servir alguna mena de proxy invers com Cloudflare per protegir la teva site, pensa que els certificats de client no funcionaran. Segurament cal alguna configuració extra dins el teu proveïdor per redirigir les peticions de certificat de client.
Per tant, si tens configurat Cloudflare, habilita un subdomini (per exemeple dnie.domini.cat) i desactiva-hi el proxy invers per tal de que la comunicació sigui directa amb el server.
Aquí s'explica la doble autenticació mútua entre servidor i client.
En aquesta documentació de INTECO disposem d'una guia per a configurar Apache amb els certificats necessaris per al DNIe, tot i que caldran algunes modificacions i actualitzacions:
ULL: aquesta configuració és obsoleta. Veure més avall l'actualitzada. Ho deixem com a documentació de les fonts.
El què es proposa a la documentació del DNIe és el què segueix.
# Configuracio DNIe # ULL: aquesta configuració és obsoleta. Veure més avall l'actualitzada <Directory /var/www/sitednie/zona-privada> # Certificado raiz DNIe SSLCACertificateFile "/etc/ssl/certs/AC RAIZ DNIE 2.crt" # El cliente debe autenticarse obligatoriamente con el certificado SSLVerifyClient require # Nivel máximo de profundidad (según infraestructura actual, 2) SSLVerifyDepth 2 # Exportar contenido de certificados y certificados (para poder usarlos con PHP) SSLOptions +StdEnvVars +ExportCertData Options Indexes FollowSymLinks MultiViews AllowOverride None Order allow,deny allow from all </Directory>
La directiva més important és la que exigeix el certificat a l'usuari que intenta entrar en aquest Directory
:
SSLVerifyClient require
Per saber més d'aquesta directiva d'Apache i les seves opcions consulta la doc oficial de SSLVerifyClient.
Canvis que cal fer:
SSLCACertificateFile
del nivell de Directory
i posar-ho al nivell de VirtualHost
. Apache ara no admet diferents certificats per directori (només un per VirtualHost).Directory
per Location
, tal i com recomana fer-ho Apache2. Per exemple, creeu una zona reservada a Location /zona-privada
.SSLOptions
i Options
també a nivell de VirtualHost (tot i que això no és imprescindible).
Un error que ens pot sorgir és que ens doni un 403 FORBIDDEN «Cannot perform Post-Handshake Authentication.» En aquest cas és per una incompatibilitat amb la implementació del protocol de seguretat amb el navegador. Per solventar-lo, només cal afegir aquesta directiva per forçar a fer servir el protocol TLSv1.2:
SSLProtocol -all +TLSv1.2
Com ja hem dit, podem realitzar aquesta instal·lació en local, tot i que és més interessant realitzar-la en un servidor públic.
Recorda que per configurar Apache2 en Debian Ubuntu hem de situar l'arxiu .conf a la carpeta sites-available
i habilitar la site amb a2ensite
.
Els certificats vàlids estan a la carpeta /etc/ssl/certs
, en symbolic links. És interessant destacar que afegir l'arxiu a la carpeta i emprar la directiva SSLCACertificatePath
no funcionarà, a la documentació s'explica que cal seguir un symbolic link amb un format de hash concret.
Necessitem descarregar els certificats arrel de l'Autoritat de Certificació (AC) del DNIe i configurar l'accés amb la directiva SSLCACertificateFile
.
La configuració que emprarem serà mitjançant l'arxiu /etc/ssl/certs/ca-certificates.crt
, on estan tots els certificats concatenats seguidament, i amb la directiva SSLCACertificateFile
. El certificat de CA de la FNMT ja hi és per defecte, però no el del DNIe. Per tant, el descarreguem, descomprimim i annexem a ca-certificates.crt
per tal d'habilitar-ho:
# cd /etc/ssl/certs # wget https://www.dnielectronico.es/ZIP/ACRAIZ-DNIE2.zip # unzip ACRAIZ-DNIE2.zip # cat "AC RAIZ DNIE 2.crt" >> /etc/ssl/certs/ca-certificates.crt
Fixeu-vos que l'arxiu de certificats el configurem amb la directiva:
SSLCACertificateFile /etc/ssl/certs/ca-certificates.crt
Finalment, la configuració d'Apache per a validació del DNIe ens quedarà com segueix.
<IfModule mod_ssl.c> <VirtualHost *:443> ServerAdmin webmaster@localhost #ServerName localhost DocumentRoot /var/www/html LogLevel debug ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined SSLEngine on # Certificats per validar HTTPS (aquests son autofirmats) SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key # Configuracio DNIe SSLCipherSuite HIGH:MEDIUM:-SSLv2 SSLProtocol -all +TLSv1.2 # Arxiu amb tots els certificats (cal afegir-hi el "AC RAIZ DNIE 2.crt") SSLCACertificateFile /etc/ssl/certs/ca-certificates.crt # Exportar contenido de certificados (para poder usarlos con PHP) SSLOptions +StdEnvVars +ExportCertData Options Indexes FollowSymLinks MultiViews <Location /zona-privada> SSLVerifyClient require #SSLVerifyClient optional_no_ca # Nivel máximo de profundidad (según infraestructura actual, 2) SSLVerifyDepth 2 AllowOverride None Order allow,deny allow from all </Location> <FilesMatch "\.(cgi|shtml|phtml|php)$"> SSLOptions +StdEnvVars </FilesMatch> <Directory /usr/lib/cgi-bin> SSLOptions +StdEnvVars </Directory> </VirtualHost> </IfModule>
Abans de fer el codi, recordeu que cal instal·lar PHP al servidor:
$ sudo apt install libapache2-mod-php
A les variables supraglobals trobaràs les dades que el client transmet al servidor, en particular les de $_SERVER
que comencen per SSL_…
, com per exemple $_SERVER['SSL_CLIENT_S_DN']
. Aquestes variables les aconseguim capturar dins el nostre llenguatge de programació (en aquest cas PHP) mitjançant la directiva d'Apache:
SSLOptions +StdEnvVars +ExportCertData
Si no està activada aquesta directiva no podrem veure les dades del client.
A aquesta web hi ha alguns exemples de com escanejar totes les variables supragrobals.
Les variables que podem fer servir son:
$_SERVER['SSL_CLIENT_S_DN']
: les dades del DNIe (nom, cognoms, número del DNI, etc.). Caldrà fer algun parse extra per aïllar les variables adientment (per exemple, extreure el número del DNI).$_SERVER['SSL_CLIENT_S_DN_G']
: el nom de pila.$_SERVER['SSL_CLIENT_S_DN_S']
: el 1r cognom.$_SERVER['SSL_CLIENT_CERT_CHAIN_0']
: issuer certificate$_SERVER['SSL_CLIENT_CERT']
: client certificate
Amb aquest codi pode examinar totes les variables que ens arribien dins l'array supraglobal $_SERVER
:
<h1>Portal DNIe</h1> <?php echo "Benvingut/da ".$_SERVER['SSL_CLIENT_S_DN_G']; echo "<br><br>\n\n"; echo "\n<table>\n"; foreach( $_SERVER as $key => $val ) { echo "<tr>\n<td>$key</td><td>$val</td></tr>\n"; } echo "\n</table>\n"; ?>
Amb la comprovació OCSP el què fem és consultar la base de dades de la pròpia CA (autoritat certificadora, la seu del DNIe) per comprovar que el certificat que ens arriba no hagi estat revocat. És una important passa de seguretat.
El resultat de la consulta OCSP hauria de ser: good, revoked o unknown.
En aquestes pàgines tenim exemples de com fer una query OCSP (a ocsp.dnie.es) per conèixer l'estat del certificat utilitzat, ja que podria estar revocat:
La 1a funciona, però cal corregir un petit error en la línia de la query que es fa mitjançant OCSP. Investiga què és el què pot fallar (la manera més fàcil és activant els missatges de error d'Apache a php.ini i mostrant les variables intermitges. Mostra també la query openssl
per veure què és el que fem executar a la shell i excecuta-la manualment en una shell a part per esbrinar quin problema ens estava succeint.
Perquè ens funcioni amb diversos tipus de certificats com idCAT, hisenda, etc. podem fer servir l'arxiu amb tots els certificats agrupats que porta Apache, al qual afegirem el del DNIe, que per defecte no ve inclòs.
# cd /etc/ssl/certs # cat AC_RAIZ_DNIE_2.crt >> ca-certificates.crt
I canviarem la línia de l'anterior arxiu de configuració on diu:
SSLCACertificateFile /etc/ssl/certs/AC_RAIZ_DNIE_2.crt
per:
SSLCACertificateFile /etc/ssl/certs/ca-certificates.crt