Smart Card Authentication - Server users.dimi.uniud.it

annuncio pubblicitario
Smart Card Authentication
Paviotti Marco
June 17, 2008
Contents
1 Specifiche
1.1 Installazione di Tomcat e JVM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1
1
2 Configurazione
2.1 Server Authentication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2 Client Authentication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
2
3
3 Avvio
4
4 Applicazione d’esempio
4.1 OpenCMS . . . . . . . . . . . . . .
4.2 La Modifica . . . . . . . . . . . . .
4.3 Uso . . . . . . . . . . . . . . . . .
4.3.1 Disabilitare il login classico
4.4 Considerazioni sulla sicurezza . . .
1
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4
4
5
6
7
7
Specifiche
La Regione FVG, come altre regioni italiane, ha distribuito a tutti i cittadini del FVG una tessera contenente una chiave privata RSA, e il relativo certificato, abilitata all’autenticazione forte. Al momento si può
impiegare tale tessera per autenticarsi solo presso il sito web della regione, ma nulla vieta di utilizzare tale
tessera presso altri siti. Si vuole studiare questa possibilità; più precisamente, si vuole definire chiaramente
come creare un sito web, o un servizio web, supportante l’autenticazione con tale smartcard.
Tessera sanitaria
1.1
Installazione di Tomcat e JVM
Per l’implementazione delle specifiche in Java sono richiesti due componenti fondamentali :
1. La Java Virtual Machine
1
2. Il web server Tomcat
L’installazione della JVM è molto semplice, dopo averla scaricata dal sito web ufficiale di Sun
(http://java.sun.com/javase/downloads/?intcmp=1281) si può procedere all’esecuzione del file binario
che estrae i file necessari in una cartella jdk-X.Y.Z creata nella working directory su cui stiamo lavorando.
L’installazione di Tomcat è altrettanto semplice, il file binario si può ottenere da http://tomcat.apache.
org/download-60.cgi e segue la stessa procedura descritta sopra.
Ambe due le installazioni non richiedono nessuna configurazione iniziale, per avviare il webserver serviranno tre semplici comandi.Assumiamo come JVM DIR la directory in cui è stata scompattata la Java virtual
Machine, e TOMCAT DIR la rispettiva directory di Tomcat, (si farà riferimento a queste due Alias per il
resto del documento):
export JAVA_HOME=$JVM_DIR
$TOMCAT_DIR/bin/startup.sh
Installazione e configurazione potrebbero variare a seconda della versione della JVM o di Tomcat, per
questo esperimento si è scelto di utilizzare JDK-1.6.0 Update 3, e Tomcat 6.0.16.
2
Configurazione
A questo punto per realizzare una configurazione in cui server e client si autentichino a vicenda serve una piccola modifica al file di configurazione di tomcat, il file in questione è situato in $TOMCAT DIR/conf/server.xml.
Esplorando tale file si nota che c’è una parte commentata relativa alla porta 8443, in primo luogo questa
sezione và decommentata, in secondo luogo bisogna modificarla . Le modifiche da fare sono minime ma
essenziali : innanzitutto dobbiamo dire a tomcat di autenticare opzionalmente anche il client (clientAuth
= “want”) dopodichè dobbiamo specificare il file (per questo esempio abbiamo usato keystoreFile= $TOMCAT DIR/keystore) dove verranno memorizzati i certificati relativi alla connessione SSL e la password per
aprire tale file (keystorePass= $PASSWORD), la sezione corrispondente al Connector per SSL diventa quindi
:
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" maxThreads="150"
scheme="https" secure="true" clientAuth="want" sslProtocol="TLS"
keystoreFile="$TOMCAT_DIR/keystore"
keystorePass="$PASSWORD">
<Factory className="org.apache.catalina.net.SSLServerSocketFactory"
clientAuth="true" protocol="TLS" keystorePass="PASSWORD"/>
</Connector>
N.B.: “Autenticare opzionalmente” significa che il server non si occuperà di controllare che il certficato
sia presente per forza, nel caso che non sia presente sarà la web application a restituire un messaggio di
errore
2.1
Server Authentication
In questa sezione dobbiamo dotare tomcat di un certificato con cui il client possa autenticare la fonte a cui ci
si stà connettendo, al momento della richiesta infatti il server manderà al browser il suo certificato e l’utente
sceglierà se fidarsi o no.Il server potrebbe disporre di un certificato valido (firmato da autorità note), ma per
il nostro scopo basta un certificato autofirmato.
Il seguente comando crea un truststore con un certificato autofirmato:
$JVM_DIR/bin/keytool -genkey -alias tomcat-keyalg RSA -keystore $TOMCAT_DIR/keystore
2
Si noti che il path per la memorizzazione è quello specificato anche in fase di configurazione del server
nel file server.xml .
Al momento della generazione del certificato verrà chiesta una password, la stessa password che và
specificata nel file di configurazione di tomcat (server.xml).
Di seguito è riportato un esempio pratico del comando :
marco@marco:~/Desktop/apache-tomcat-6.0.16$ /home/marco/jdk1.6.0_03/bin/keytool -genkey
-alias tomcat -keyalg RSA -keystore /home/marco/Desktop/apache-tomcat-6.0.16/keystore
Enter keystore password:
Re-enter new password:
What is your first and last name?
[Unknown]: Marco Paviotti
What is the name of your organizational unit?
[Unknown]:
What is the name of your organization?
[Unknown]:
What is the name of your City or Locality?
[Unknown]: Udine
What is the name of your State or Province?
[Unknown]: Italy
What is the two-letter country code for this unit?
[Unknown]: IT
Is CN=Marco Paviotti, OU=Unknown, O=Unknown, L=Udine, ST=Italy, C=IT correct?
[no]: yes
Enter key password for <tomcat>
(RETURN if same as keystore password):
Re-enter new password:
2.2
Client Authentication
A questo punto il server ha il suo certificato, sà che deve autenticare il client, e quindi tramite SSL richiede
il certificato del client.Il browser connesso dall’altra parte deciderà (prova i certificati in sequenza o chiede
un input dall’utente) che certificato inviare, dopodichè il server riceve il certificato e verifica la firma in esso
contenuta.
Il certificato dev’essere firmato da un’autorità fidata (Thawte, VerySign.. per esempio) altrimenti il web
server non potrà validare la richiesta ed essere sicuro dell’ identità del client. Se il certificato è firmato da
una autorità di cui tomcat non si fida (o che semplicemente non è presente nel database delle certification
autorities) il server risponderà con un messaggio di errore:
Could not enstablish an encrypted connection because your certificate was rejected by localhost.
Error Code : -12271
Per questo tipo di esperimento ci serve quindi il certificato della Certification Authority che ha firmato
i certificati delle Smart Card del Friuli. Una volta ottenuto bisogna aggiungerlo ai certificati della autorità
fidate con il seguente comando.
$JVM_DIR/bin/keytool -import -keystore $JVM_DIR/jre/lib/security/cacerts \ -storepass
$PASSWORD -alias rootca -file ca_cittadini.cer -trustcacerts
Dove ca cittadini.cer è il certificato della Root Authority.
3
3
Avvio
Non resta che avviare il server con il comando indicato anche all’inizio di questa guida :
export JAVA_HOME=$JVM_DIR
$TOMCAT_DIR/bin/startup.sh
Attenzione : l’output del comando startup.sh è sempre identico ed è simile a questo :
Using
Using
Using
Using
CATALINA_BASE:
/home/marco/Desktop/apache-tomcat-6.0.16
CATALINA_HOME:
/home/marco/Desktop/apache-tomcat-6.0.16
CATALINA_TMPDIR: /home/marco/Desktop/apache-tomcat-6.0.16/temp
JRE_HOME:
/home/marco/jdk1.6.0_03/
ma per verificare se ci sono stati eventuali malfunzionamenti o errori di configurazione bisogna guardare
il log di tomcat :
tail -f $TOMCAT_DIR/logs/catalina.out
Se tutto è andato a buon fine e il server è up, ci si può connettere, con un browser configurato per acquisire
il certificato dalla smart card (per la configurazione del browser si segua la guida sul sito ufficiale della carta
servizi http://cartaservizi.regione.fvg.it/CRSPortale/Index.jsp?STATO=FEComeAccedo.jsp), all’indirizzo
https://localhost:8443/ (eventualmente con il nome dell’applicazione installata in fondo all’URL); il
server risponder con il proprio certificato lasciando all’utente (client) la facoltà di decidere se accettarlo o
meno nel caso che questo non sia in grado di verificare l’identità della certification authority.
Dopodichè sarà la volta del client : il browser chiederà all’utente quale certificato usare e lo invierà al
server.
4
Applicazione d’esempio
A questo punto se le due parti sono state autenticate correttamente possiamo installare la nostra applicazione
per autenticare gli utenti. Nel caso generale l’applicazione dovrà prendere il certificato del client e verificare
che il soggetto identificato dal campo CN sia presente nel proprio database degli utenti.
4.1
OpenCMS
Nel nostro caso abbiamo scelto di usare un CMS, opencms. Questo CMS prevede una schermata di login
iniziale per dare accesso alla parte amministrativa del software e sarà qui che andremo a intervenire per farci
autenticare via CNS.
La form di login ha come action la pagina /opencms/opencms/system/login/index.html la quale sostanzialmente inizializza la classe CMSLogin e chiama il metodo di displayDialog() :
<%@ page import=” o r g . opencms . w o r k p l a c e . ∗ ” %><%
CmsLogin wp = new CmsLogin ( pageContext , r e q u e s t , r e s p o n s e ) ;
%><%= wp . d i s p l a y D i a l o g ( ) %>
displayDialog a seconda dei parametri passati stampa l’html di output.
1. login : se true indica alla web-page che si stà eseguendo il login, di conseguenza verifica i parametri
ocUname e ocPword.
2. requestedResource : la pagina richiesta .
3. ocUname : username.
4. ocPword : password.
La classe CMSLogin e contenuta nel package org.opencms.workplace
4
4.2
La Modifica
Per raggiungere i nostri scopi aggiungiamo un altro parametro : certificate. In particolare vogliamo che, nel
caso questo parametro sia true, la pagina salti il login convenzionali e guardi solo ai certificati.
Il codice seguente verifica la variabile certificate caricata in precendenza nel costruttore, se questa a true
1. carica il certificato dalla Request, sostituisce l’username con il codice fiscale e forza il codice a effettuare
il login impostando m actionLogin = true (la corrispondente variabile all’interno della pagina che
contiene il valore login della form)
2. se il certificato non è stato caricato imposta le variabili m username e m password a null e il m actionLogin
a true in modo che al controllo successivo venga ritornato un messaggio di errore specificato dalla
variabile Messages.ERR NO CERT della classe org.opencms.workplace.Messages e impostato nel file
messages.properties
i f ( c e r t i f i c a t e != null && c e r t i f i c a t e . e q u a l s ( ” t r u e ” ) ) {
X509Certificate certChain [ ] = ( X509Certificate [ ] ) getRequest ( )
. getAttribute ( ” javax . net . s s l . p e e r c e r t i f i c a t e s ” ) ;
i f ( ( c e r t C h a i n == null ) | | ( c e r t C h a i n . l e n g t h == 0 ) ) {
certChain = ( X509Certificate [ ] ) getRequest ( )
. getAttribute ( ” javax . s e r v l e t . request . X509Certificate ” ) ;
}
i f ( c e r t C h a i n != null && c e r t C h a i n . l e n g t h > 0 ) {
c o d i c e F i s c a l e = c e r t C h a i n [ 0 ] . getSubjectDN ( ) . getName ( ) ;
codiceFiscale = codiceFiscale . substring (
”CN=%22” . l e n g t h () −2 ,
c o d i c e F i s c a l e . indexOf ( ” / ” ) ) ;
m username = c o d i c e F i s c a l e ;
m actionLogin = ” true ” ;
m password = ” ” ;
} else {
m username = null ;
m password = null ;
m actionLogin = ” true ” ;
}
}
Più avanti nel codice, a seguito dell’impostazione a true della varibile m actionLogin, il programma
eseguirà il login utilizzando la funzione login():
l o g i n ( ( m oufqn == null ? C m s O r g a n i z a t i o n a l U n i t .SEPARATOR : m oufqn )
+ m username , m password ) ;
Questa riga andrà poi sostituita con il codice seguente in quanto noi vogliamo che la verifica, nel caso
sia stata richiesta l’autenticazione tramite certificati, avvenga solo per l’username; per raggiungere questo
obbiettivo usiamo la funzione login() utilizzando come parametri d’accesso l’username e la password entrambi
uguali al codice fiscale, e nell’username aggiungiamo la stringa “–CNS–:” per far capire alla classe che andrà
a verificare l’utente nel db che non ci servirà la verifica della password:
i f ( c e r t i f i c a t e != null && c e r t i f i c a t e . e q u a l s ( ” t r u e ” ) ) {
l o g i n ( ( m oufqn == null ? C m s O r g a n i z a t i o n a l U n i t .SEPARATOR : m oufqn )
+ ”−−CNS−−:” + m username , m username ) ;
5
} else {
i f ( m username . c o n t a i n s ( ”−−CNS−−:” ) ) {
throw new IOException ( ” I m p o s s i b i l e a u t e n t i c a r e l ’ u t e n t e ” ) ;
}
l o g i n ( ( m oufqn == null ? C m s O r g a n i z a t i o n a l U n i t .SEPARATOR : m oufqn )
+ m username , m password ) ;
}
A questo punto dobbiamo individuare il codice che verifica le credenziali di accesso nel db, la classe in
questione è org.opencms.db.CMSDriverManager.
La parte modificata è nel metodo loginUser, qui la modifica è molto semplice : se l’username contiente
la stringa “–CNS–:” vuol dire che l’username proviene da un certificato, per cui non serve verificare anche
la password, basterà verificare che l’utente esista nel db, quindi ci preoccuperemo di togliere semplicemente
la stringa incriminata e di passare l’username alla funziona readUser.
Nel caso questo non esista viene lanciata una eccezione CmsAuthentificationException, altrimenti esiste
viene restituita la variabile newUser;
Se l’username non contiene “–CNS–:” allora si eseguirà la procedura di login convenzionale.
i f ( userName . c o n t a i n s ( ”−−CNS−−:” ) ) {
try {
newUser = r e a d U s e r ( dbc , userName . s u b s t r i n g ( 0 , userName . indexOf ( ”−−CNS−−:” ) )
+ userName . s u b s t r i n g ( userName . indexOf ( ”−−CNS−−:” )+8 , userName . l e n g t h ( ) ) ) ;
} catch ( CmsDataAccessException e2 ) {
throw new C m s A u t h e n t i f i c a t i o n E x c e p t i o n ( o r g . opencms . s e c u r i t y . Messages . g e t ( ) . c o n t a i n e r (
o r g . opencms . s e c u r i t y . Messages . ERR LOGIN FAILED 2 ,
userName , remoteAddress ) , e2 ) ;
}
} else {
newUser = m u s e r D r i v e r . r e a d U s e r ( dbc , userName , password , remoteAddress ) ;
}
4.3
Uso
Apriamo il seguente URL per verificare che tutto funzioni: https://localhost:8443/opencms/opencms/
system/login/index.html
Verrà visualizzata una pagina come quella nella figura sottostante in cui si potrà utilizzare l’account
per l’amministrazione al fine di aggiungere utenti associati al codice fiscale, oppure si potrà seguire il link
sottostante alla form per eseguire l’autenticazione per mezzo della CNS.
Login
Se il codice fiscale contenuto nella CNS è presente anche nella lista degli utenti di opencms, allora la
pagina seguente sarà di conferma dell’avvenuta autenticazione:
6
Autenticazione effettuata con successo
4.3.1
Disabilitare il login classico
L’amministratore può impedire il login tradizionale per gli utenti che usano l’autenticazione con Smart Card,
impostando per questi ultimi una password random (ad esempio di 50 caratteri ed oltre) senza comunicargliela. In questo modo tali utenti non possono usare il login con user/password, e quindi sono obbligati a
passare al login via smartcard.
Questa soluzione è efficace pur non essendo troppo elegante; l’implementazione di una funzionalità analoga
nel codice di OpenCMS è possibile, ma comporta la modifica di molti moduli amministrativi del software.
4.4
Considerazioni sulla sicurezza
Un utente potrebbe tentare un uso non corretto della stringa “–CNS–:” anteponendola ad un codice fiscale.
Questo è impedito dalla seguente condizione :
if(m_username.contains("--CNS--:"))
Se quest’espressione è vera ed è stato effettuato il login normale (cioè senza smart card) si lancia un
eccezione .
Un attaccante potrebbe inoltre tentare di usare una stringa del genere, impostando certificate=true e
selezionando il codice fiscale di un altro utente :
https://localhost:8443//opencms/opencms/system/login/index.html
?certificate=true&login=trueo&cUname=$codiceFiscaleAltri
in questo caso, siccome è stata richiesta l’autenticazione per mezzo di certificati SSL, anche se cUname
viene inviato in ogni caso in query string (o POST data), quest’ultima sovrascrive il parametro con quello
contenuto nel certificato.
7
Scarica