• Non ci sono risultati.

CAPITOLO 5 – PROGETTO PROTOTIPO

5.3 SICUREZZA DEGLI ACCESSI

5.3.7 Controllo accessi tramite indirizzi IP

Ogni sito web che richiede l’autenticazione dell’utente risulta essere un buon candidato per essere soggetto ad un attacco di tipo brute force. Si tratta di un tentativo di scoprire una password in un’area protetta provando sistematicamente ogni possibile combinazione di lettere, numeri e simboli, fino a trovare quella giusta. La Fondazione ha migliaia di pazienti, quindi ricorrendo a dei generatori di Codici Fiscali non è impossibile individuarne qualcuno esatto, mentre per quanto riguarda la password OTP la cosa è un po’ più complessa. Questo tipo di attacchi, oltre che a mettere a rischio l’account dell’utente, inondano il sito con traffico inutile. Mentre da un lato la procedura sembra apparentemente semplice da attuare per un malintenzionato, dall’altro potrebbero essere richiesti anni per portarla a buon fine. Infatti, a seconda della lunghezza della password e della sua complessità, ci potrebbero essere migliaia di miliardi di combinazioni possibili. Per

accelerare un po’ la procedura, in alcuni casi un attacco brute force inizia con parole estratte dal dizionario o parole del dizionario leggermente modificate, dato che la maggior parte delle persone usa parole comuni invece che password completamente casuali. Una prima prevenzione fa leva proprio su questo aspetto e dunque è già stata descritta quando è stata illustrata la scelta di password generate casualmente ed aventi un tempo di validità limitato. Alcune condizioni che potrebbero essere indice di un attacco brute force in corso sono:

 Molti accessi non riusciti dallo stesso indirizzo IP;

 Accessi con più nomi utente dallo stesso indirizzo IP;

 Tentativi di accesso per un singolo account provenienti da molti indirizzi IP diversi;

 Utilizzo eccessivo di banda per un singolo uso;

 Tentativi di accesso falliti utilizzando nomi in ordine alfabetico o sequenze crescenti di numeri.

Tenendo conto di alcuni di questi aspetti, un lavoro di prevenzione è stato fatto implementando dei controlli ricorrendo al Database Oracle e a funzioni Java. La logica seguita consiste nello stabilire un numero massimo di tentativi errati, oltre al quale viene fatto scattare un blocco dell’indirizzo IP che ha fatto le richieste. Dopo il numero massimo di tentativi non è più possibile tentare l’autenticazione per i successivi 30 minuti. Dal punto di vista pratico, ciò che è stato fatto è la creazione di una tabella aggiuntiva a quelle che permettono la gestione dell’autenticazione. Questa tabella contiene un campo “IP” nel quale viene registrato appunto l’IP del client in caso di fallimento del login, un campo TIMESTAMP e un campo ERRORI che tiene conto del numero di tentativi errati associati a quell’IP.

CREATE TABLE “GESTIONE_IP” (

"IP" VARCHAR2(20 BYTE) NOT NULL ENABLE, "ERRORI" NUMBER(1,0) DEFAULT 1,

"TIMESTAMP" VARCHAR2(20 BYTE),

CONSTRAINT "GESTIONE_IP" PRIMARY KEY ("IP") );

Passiamo adesso alla logica gestita in linguaggio Java. Vediamo alcune costanti di configurazione. int TimeBlock = 1800;

int MaxErr = 5;

La costante TimeBlock definisce il tempo di blocco dell’IP in secondi; in questo caso si tratta di 30 minuti. MaxErr invece definisce il numero massimo di errori oltre il quale scatta il blocco. Il metodo Lock si occupa, in caso di errore nel login, di aggiungere un record nel database associato all’IP oppure, nel caso in cui il record esista già, di incrementarne il valore del campo ERRORI. Ciò che viene restituito dal metodo è il numero di tentativi residui.

private static int Lock(String IP, Statement st, String time) { int MaxErr=5;

int ErrRes; try {

ResultSet rs=st.executeQuery("SELECT ERRORI FROM GESTIONE_IP WHERE IP='"+IP+"'"); if(rs.next()){

ErrRes = rs.getInt("ERRORI");

st.executeUpdate("UPDATE GESTIONE_IP SET ERRORI=ERRORI+1, TIMESTAMP='"+time+"' WHERE IP = '"+IP+"'");

ErrRes=MaxErr - ErrRes; return ErrRes;

}

st.executeQuery("INSERT INTO GESTIONE_IP (IP, TIMESTAMP) VALUES ('"+IP+"', '"+time+"')"); } catch (SQLException e) { e.printStackTrace(); } return MaxErr; }

La prima query controlla se esiste già un record relativo all’IP del dispositivo che sta eseguendo la richiesta. Se questo esiste, aggiorna il timestamp ed incrementa di uno il valore contenuto in ERRORI, altrimenti crea il record. La seguente linea di codice invece si occuperà di cancellare l’eventuale record associato ad un IP nel caso in cui l’autenticazione sia andata a buon fine.

st.executeUpdate("DELETE FROM GESTIONE_IP WHERE IP = '"+ IP +"'");

Il metodo isLock si occupa, nel momento in cui viene effettuata una richiesta, di controllare se l’indirizzo IP risulta essere bloccato o meno, e quindi mette in atto le procedure corrispondenti alla situazione rilevata. Il metodo restituisce il tempo di blocco rimanente se l’utente risulta bloccato, zero altrimenti.

private static long isLock(String IP, Statement st, String time) { int MaxErr = 5;

DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); df.setTimeZone(TimeZone.getTimeZone("GMT+1:00"));

try {

ResultSet rs=st.executeQuery("SELECT * FROM GESTIONE_IP WHERE IP='"+IP+"'"); if(rs.next()){

int Errori = Integer.parseInt(rs.getObject("ERRORI").toString()); String TIMESTAMP = rs.getObject("TIMESTAMP").toString();

Date TimeSTOP = df.parse(TIMESTAMP); Date CurrentTime = df.parse(time); if(Errori > MaxErr){

if(CurrentTime.compareTo(TimeSTOP)>0){

System.out.print("Blocco IP terminato. ");

st.executeUpdate("DELETE GESTIONE_IP WHERE IP = '"+IP+"'"); return 0;

}else{

long diff = TimeSTOP.getTime() - CurrentTime.getTime(); return diff; } } } } catch (SQLException e) { e.printStackTrace(); } catch (ParseException e) { e.printStackTrace(); }

System.out.print("Indirizzo IP non bloccato | "); return 0;

In prima battuta viene verificato se esiste una riga nel database contenente l’IP: se il ResultSet è vuoto l’IP non risulta bloccato. In caso contrario viene verificato se il numero di tentativi è maggiore rispetto a quello massimo definito. Se lo è, ed il timestamp corrente è maggiore del tempo di blocco, l’utente è abilitato altrimenti gli viene segnalato che il suo indirizzo IP ha subito un blocco momentaneo e vengono interrotte le operazioni. Quindi, nel metodo principale che gestisce l’autenticazione, come prima cosa viene invocato IsLock() in modo che se viene riscontrata una situazione di blocco, la procedura si arresta lì.

if(isLock(IP, Statement, utcTime)){ return;

}

Se l’autenticazione dovesse andare a buon fine si procede secondo la modalità standard, in caso contrario viene invocato il metodo Lock() che provvederà a creare o ad incrementare il contatore del record nel database. Una considerazione che è opportuno fare è che molti strumenti adoperati per effettuare un attacco brute force utilizzano liste di proxy server e inviano da ogni indirizzo IP solo alcune richieste, per poi passare all’indirizzo successivo. Quindi non è impossibile aggirare un meccanismo di blocco IP di questo tipo. Un utente malintenzionato con una lista di 1000 proxy può tentare 2000 o 3000 password senza essere bloccato. Altre tecniche, non implementate, e che potrebbero essere prese in considerazione per arginare questo problema sono:

 Dare la possibilità agli utenti di consentire l'accesso solo da determinati indirizzi IP;

 Utilizzare un Captcha per prevenire gli attacchi automatizzati.

L’utilizzo dei Captcha tuttavia è stata scartata dopo un’analisi preliminare tenendo conto del target di soggetti, soprattutto anziani, verso i quali è rivolta l’applicazione. Arrivati a questo punto, è stato descritto il quadro completo del processo di autenticazione, il quale può essere riassunto per comodità nel seguente diagramma di flusso.