• Non ci sono risultati.

CAPITOLO 5 – PROGETTO PROTOTIPO

5.3 SICUREZZA DEGLI ACCESSI

5.3.6 Controlli sugli input

Mentre l’utilizzo di firewall e della crittografia SSL consentono rispettivamente di proteggere l'utente da attacchi a livello di rete e dall'intercettazione dei dati in transito sulla stessa, nessuna di queste due opzioni offre una reale protezione dagli attacchi di tipo SQL Injection. Gli attacchi di iniezione di codice sono mirati a colpire applicazioni web che si appoggiano su un DBMS di tipo SQL e funzionano tutti sullo stesso principio: un utente malintenzionato inserisce del codice dannoso attraverso un campo di input dell'applicazione con lo scopo di alterare l’interrogazione al database, ottenendo dei risultati impredicibili da parte del programmatore. Nello scenario peggiore l’hacker può riuscire ad accedere ad alcuni dati senza averne l’autorizzazione, ad eludere il sistema di autenticazione e addirittura a far eseguire veri e propri comandi al server web manipolando il database stesso. Consideriamo ad esempio un possibile scenario estratto dall’applicazione implementata:

<h2>Login</h2>

<form action="JavaScript:invia_CF ()">

Inserisci il Codice Fiscale: <input type="text" id="username" size="16"> <input type="submit" value="Invia">

</form>

Per ricevere la password OTP tramite SMS e per poter procedere con la seconda parte della procedura di autenticazione, l'utente visualizza una form e compila i dati inserendo il proprio Codice Fiscale che verrà processato dalla funzione JavaScript invia_CF(), la quale si occuperà di

effettuare una richiesta di tipo Ajax per scambiare in maniera asincrona i dati con il Web Server. Il codice inserito verrà utilizzato da una query SQL di questo tipo (vedi variabile “username”):

SELECT RECORD FROM TABELLA WHERE CODICE = ‘"+username+"’

Se lo script non compie i dovuti controlli, è possibile inserire nel campo di input una stringa SQL scritta in maniera opportuna, ottenendo una risposta diversa rispetto a quella prevista.

STRINGA MALIGNA INSERITA NEL CAMPO INPUT: Prova’; DELETE FROM PAZIENTE - -

SELECT RECORD FROM TABELLA WHERE CODICE = ’ Prova’; DELETE FROM TABELLA --'

Pertanto, per garantire un certo livello di protezione, è necessario prevenire questo tipo di attacchi effettuando dei controlli sui dati ricevuti in input ed impostando le query in modo da non renderle predisposte alla vulnerabilità. L’unico modo efficace per difendersi dagli attacchi di iniezione di codice maligno è dunque quello di validare tutti gli input dell’utente. Una strategia potrebbe essere quella di definire una black-list, ovvero un elenco di caratteri pericolosi che devono essere bloccati (ad esempio l’apostrofo ‘, il doppio trattino --, il punto e virgola ed il punto); questo però risulta essere un approccio abbastanza limitato, dato che non si può avere la certezza di essere riusciti a coprire tutte le possibilità esistenti. Il modo più corretto per convalidare l'input è invece quello di prevedere invece una white-list, ovvero un elenco di opzioni consentite. Per quanto riguarda la form del Codice Fiscale viene implementato, come vedremo dettagliatamente tra poco, un controllo sulla validità della forma del codice inserito e del tipo di caratteri utilizzati, mentre per la form di input della OTP la white-list consentirà solo l’inserimento di una password di una determinata lunghezza e costituita solamente da caratteri numerici. Ciò permette dunque di contrastare un attacco specificando il formato corretto dei dati inseriti nel campo di input: l'applicazione rifiuterà gli input che non si adattano al formato stabilito.

private static String ControlloOTP(String psw) { if(psw.length() == 0){

return "Campo vuoto."; }

if( psw.length() != 8 ){

return "La password deve essere costituita da 8 cifre."; }

- - commenta la parte finale della query query SQL

concatenata il ; indica di terminare

la seguente query ed eseguirne un’altra

else {

if(isNumeric(psw)) return "ok"; else{

return "Sono permessi solo caratteri numerici."; }

} }

Questo approccio (a differenza di una blacklist) può prevenire non solo gli attacchi attualmente noti, ma può costituire anche uno strumento di prevenzione nei confronti di nuove tipologie future di attacchi. Per essere ancora più accurato, lo sviluppo potrebbe prevedere entrambe le liste: in questo modo la white-list verrebbe utilizzata per bloccare la maggior parte degli attacchi, mentre la black- list proteggerebbe da casi più specifici e che potrebbero non venire filtrati dall’altra. Un ulteriore aspetto da considerare riguarda la scelta della classe utilizzata per eseguire le istruzioni SQL una volta creata la connessione con il Database: la scelta è tra gli Statement ed i PreparedStatement. La differenza sostanziale sta nel fatto che la prima prende il comando SQL come stringa o come concatenazione di stringhe, mentre la seconda inserisce i parametri effettuandone il type checking, ed effettua l’escape nel caso vengano rilevati dei caratteri speciali. Pertanto, quando vengono inseriti parametri di provenienza non fidata, l’utilizzo della classe PreparedStatement invece della Statement, aiuta a prevenire attacchi di tipo SQL Injection. Per quanto riguarda il Codice Fiscale, questo è utilizzato come username nella procedura di autenticazione in quanto costituisce uno strumento che permette di identificare in modo univoco, ai fini fiscali e amministrativi, i cittadini nati e domiciliati nel territorio italiano. Il Codice Fiscale, che viene assegnato dall’Agenzia delle Entrate, è costituito da 16 caratteri alfanumerici ed in particolare si compone di tre lettere che rappresentano le prime tre consonanti del cognome (se sono insufficienti, dopo vengono utilizzate anche le vocali), tre lettere che rappresentano le consonanti del nome (se il nome contiene quattro o più consonanti, si scelgono la prima, la terza e la quarta, altrimenti le prime tre in ordine mentre se il nome non ha consonanti a sufficienza, si prendono anche le vocali), due cifre che rappresentano l’anno di nascita, una lettera che rappresenta il mese di nascita, due cifre che rappresentano il giorno di nascita ed il sesso (si prendono le due cifre del giorno di nascita e per i soggetti di sesso femminile, a tale cifra va sommato il numero 40), quattro caratteri alfanumerici che appresentano il Codice Catastale del comune di nascita e infine una lettera che rappresenta il carattere di controllo, che viene ricavato a partire dai primi quindici caratteri tramite un algoritmo che opera nel modo seguente:

1. Si pone la variabile s = 0;

2. Si considerano i caratteri di posto dispari dal primo al quindicesimo e si convertono in numeri secondo questa tabella:

CARATTERI ALFANUMERICI DISPARI

Carattere Valore Carattere Valore Carattere Valore Carattere Valore

0 1 9 21 I 19 R 8 1 0 A 1 J 21 S 12 2 5 B 0 K 2 T 14 3 7 C 5 L 4 U 16 4 9 D 7 M 18 V 10 5 13 E 9 N 20 W 22 6 15 F 13 O 11 X 25 7 17 G 15 P 3 Y 24 8 19 H 17 Q 6 Z 23

3. I numeri corrispondenti a ciascun carattere vanno sommati ad s;

4. Si considerano i caratteri di posto pari dal secondo al quattordicesimo e si convertono in numeri secondo questa tabella (notare che alle cifre corrisponde il valore stesso, mentre alle lettere A-Z corrispondono i numeri 0-25):

CARATTERI ALFANUMERICI PARI

Carattere Valore Carattere Valore Carattere Valore Carattere Valore

0 0 9 9 I 8 R 17 1 1 A 0 J 9 S 18 2 2 B 1 K 10 T 19 3 3 C 2 L 11 U 20 4 4 D 3 M 12 V 21 5 5 E 4 N 13 W 22 6 6 F 5 O 14 X 23 7 7 G 6 P 15 Y 24 8 8 H 7 Q 16 Z 25

5. I numeri corrispondenti a ciascun carattere vanno sommati ad s. 6.

Si calcola il resto della divisione di s per 26:

r = s%26 cioè r = s - 26*int(s/26); risulta un numero tra 0 e 25; 7. Si converte r in una lettera associando a 0 la A, a 1 la B, ...,a 25 la Z.

Figura 31 – Esempio di Codice Fiscale. Esempio: RSS MRA 85T10 A562S

1. s = 0

2. s = 8 + 12 + 8 + 19 + 14 + 1 + 13 + 5 3. s = 18 + 12 + 0 + 5 + 1 + 0 + 6 = 122 4. r = 67%26 = 18

5. Al 18 corrisponde la lettera ‘S’

In prima battuta dunque si potrebbe pensare di verificare l’attendibilità del Codice Fiscale inserito tramite un’analisi della validità del carattere di controllo. Questo tuttavia non garantisce al 100% che il codice inserito sia corretto, e potrebbe dar luogo a dei falsi negativi. Infatti, se due o più persone presentato dati anagrafici uguali, queste avranno anche lo stesso Codice Fiscale; questo fenomeno, che prende il nome di omocodia, è abbastanza diffuso e se ne verificano circa 1400 nuovi casi ogni anno. In queste situazioni si provvede alla correzione del codice, sostituendo uno o più dei sette numeri, a partire da quello più a destra, con delle lettere corrispondenti:

0 = L | 1 = M | 2 = N | 3 = P | 4 = Q 5 = R | 6 = S | 7 = T | 8 = U | 9 = V

A seguito dell’attuazione di questa procedura, la verifica della correttezza del carattere di controllo per via algoritmica perde di significato, dato che utenti che presentano un Codice Fiscale che ha subito una correzione potrebbero vedersi negare l’accesso pur avendo una credenziale valida. Nell’applicazione realizzata ci si è limitati al solo controllo della struttura del Codice Fiscale, ovvero verificare la presenza dei caratteri consentiti nelle varie posizioni, secondo lo schema previsto e di seguito riportato:

 lettere per il nome;

 lettere per il cognome;

 numeri per l’anno di nascita;

 1 lettera per il mese di nascita;

 numeri per il giorno di nascita;

 caratteri alfanumerici per il comune di nascita;

L’obiettivo e quello di ostacolare l’inserimento di codici maligni e segnalare all’utente eventuali errori di sintassi, prevenendo così banali errori di trascrizione.

private static String ControlloCF(String cf) { if( cf == "" ){

System.out.println("Campo vuoto."); return "Campo vuoto.";

}

cf = cf.toUpperCase(); if( cf.length() != 16 ){

System.out.println("Il codice fiscale deve essere lungo 16 caratteri."); return "Il codice fiscale deve essere lungo 16 caratteri.";

}

String validi = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; String alfa = "ABCDEFGHIJABCDEFGHIJKLMNOPQRSTUVWXYZ"; String num = "0123456789LMNPQRSTUV";

for(int i = 0; i < 16; i++ ){

if(i==0 || i==1 || i==2 || i==3 || i==4 || i==5 || i==8){ if( alfa.indexOf( cf.charAt(i) ) == -1 ){

System.out.println("Formato codice fiscale non valido."); return "Formato codice fiscale non valido.";

}

}

if(i==6 || i==7 || i==9 || i==10){

if( num.indexOf( cf.charAt(i) ) == -1 ){

System.out.println("Formato codice fiscale non valido."); return "Formato codice fiscale non valido.";

}

}

if(i==11 || i==12 || i==13 || i==14 || i==15){ if( validi.indexOf( cf.charAt(i) ) == -1 ){

System.out.println("Formato codice fiscale non valido."); return "Formato codice fiscale non valido.";

}

}

}

return "ok"; }

Questi controlli sono stati utilizzati unitamente ad altre misure e regole di progettazione, come ad esempio l’oscuramento delle credenziali di accesso mediante algoritmi Hash, così da evitare che le informazioni sensibili siano memorizzate in chiaro nel Database.