Progettazione e realizzazione di un nodo di elaborazione per il rilevamento distribuito di defacement con tecnologia Java Enterprise
1. UNIVERSITÀ DEGLI STUDI DI TRIESTE
FACOLTÀ DI INGEGNERIA
Corso di Laurea Specialistica in Ingegneria Informatica
Anno Accademico 2007/2008
PROGETTAZIONE E REALIZZAZIONE
DI UN NODO DI ELABORAZIONE
PER IL RILEVAMENTO DISTRIBUITO DI
DEFACEMENT
CON TECNOLOGIA JAVA ENTERPRISE
Relatore: prof. Alberto Bartoli
Correlatore: prof. Eric Medvet
Laureando: Mauri Marco
2. 1 - SOMMARIO
1 - SOMMARIO ........................................................................................................ 2
2 - INTRODUZIONE .................................................................................................. 4
3 - SCENARIO DEL PROGETTO .................................................................................. 5
3.1 SCOPO DEL PROGETTO ...........................................................................................5
3.2 WEB DEFACEMENT .................................................................................................5
3.2.1 TIPOLOGIE DI ATTACCHI ...................................................................................7
3.3 STRUTTURA DEL PROGETTO ...................................................................................9
3.4 COMPITI DEL NODO DI ELABORAZIONE ...............................................................10
4 - IMPLEMENTAZIONE DEL NODO DI ELABORAZIONE ........................................... 12
4.1 TECNOLOGIE UTILIZZATE ......................................................................................12
4.2 ANALISI DETTAGLIATA DEL NODO DI ELABORAZIONE .........................................13
4.2.1 ANALISI DI UNA PAGINA WEB ........................................................................15
4.2.2 SCHEDULING DEI TASK ...................................................................................17
4.2.3 DOWNLOAD DI UNA PAGINA WEB ................................................................18
4.2.4 COMUNICAZIONE TRA NODO E CONTROLLORE ............................................21
4.2.5 PROPAGAZIONE DEGLI ALERT ........................................................................27
4.2.6 INDICI DI CARICO ............................................................................................27
4.2.7 CLUSTERING DEI NODI DI ELABORAZIONE .....................................................28
5 - CONCLUSIONI ................................................................................................... 30
5.1 OBBIETTIVI RAGGIUNTI ........................................................................................30
5.2 PRINCIPALI PROBLEMI REALIZZATIVI ....................................................................30
5.2.1 CLUSTERING DI GLASSFISH .............................................................................30
5.2.2 SEPARAZIONE TRA INTERFACCIA GRAFICA E CONTROLLORE ........................31
2
4. 2 - INTRODUZIONE
Questo lavoro intende sviluppare una componente di un progetto software per la
rilevazione automatica di web defacement, la parte trattata in questa tesi consiste
nella scrittura della parte atta ad elaborare le pagine web.
Il software elaborato analizza le pagine web e le relative dipendenze trovando
eventuali defacement e rendendo disponibili i risultati alle altre componenti del
progetto.
Lo sviluppo di questo applicativo è stato motivato dalla grande diffusione di
defacement, e dal desiderio di creare una soluzione semplice ed economica al
problema, senza porre limitazione agli sviluppatori delle pagine web stesse. Il
progetto è, in effetti, iniziato già da alcuni anni con un piccolo gruppo di lavoro che ha
svolto lo studio iniziale sugli algoritmi da utilizzare e la progettazione del programma
finale.
Per la realizzazione del tutto si è deciso di utilizzare la piattaforma Java in quanto già
precedentemente utilizzata da tutti i membri dello staff ed in particolare quella
Enterprise in quanto forniva già molte delle funzionalità richieste. Un ulteriore
vantaggio di questa scelta è l’indipendenza dal sistema operativo utilizzato: in effetti
durante lo sviluppo del software sono stati utilizzati, senza problemi di sorta, più
sistemi operativi in contemporanea.
Per quanto riguarda il salvataggio dei dati, l’uso di Java Enterprise rende l’applicativo
indipendente dal DBMS utilizzato, durante lo sviluppo sono stati testati MySQL e
PostgreSQL, senza trovare alcuna differenza durante l’esecuzione.
Di seguito vengono trattati in modo più completo le seguenti parti:
Scenario del progetto: in questa sezione viene esposto in maniera più estesa
lo scopo del progetto, le sue motivazioni e le scelte architetturali fatte
Implementazione del nodo di elaborazione: in questa sezione viene trattata in
maniera dettagliata la struttura della parta svolta, con particolare riguardo per
il workflow dell’analisi di una pagina web
Conclusioni: in questa sezione vengono esposte in maniera particolareggiata
gli obiettivi raggiunti, i problemi riscontrati e le soluzioni adottate, ed anche le
osservazioni personali
Appendice: in questa sezione viene semplicemente riportato il documento dei
requisiti e delle specifiche redatto prima dello sviluppo del software
4
5. 3 - SCENARIO DEL PROGETTO
3.1 SCOPO DEL PROGETTO
Lo scopo di questo progetto è la realizzazione di una infrastruttura software in grado
di rilevare in maniera automatica i defacement tramite il monitoraggio del contenuto
di una pagina web in modo tale da ridurre il più possibile il tempo tra il defacement
stesso di un sito e la sua correzione.
Partendo da questo concetto astratto è stato compilato un documento contenente i
requisiti e le specifiche di partenza da cui poi è stato sviluppato il progetto vero e
proprio. In appendice viene riportato tale documento.
3.2 WEB DEFACEMENT
Un web site defacement è un attacco remoto che consiste nel modificare una pagina
web in modo non autorizzato, la rilevanza di questo fenomeno è manifesta: Zone-H
(http://www.zone-h.org) un archivio pubblico dedicato alla raccolta di prove di
defacement ha raccolto approssimativamente 490.00 defacement durante il 2005,
cifra corrispondente a più di 1300 pagine web de facciate al giorno.
I defacement web sono inclusi nell’annuale “CSI/FBI Computer Crime and Security
Survey” a partire dalla sua 9° edizione (2004). Secondo le ultime edizioni di questo
rapporto i defacement sono una delle poche categorie di attacchi in crescita.
Un sito defacciato consiste tipicamente solo di un paio di messaggi o immagini che
rappresentano una specie di firma dell’hacker che lo ha conseguito, talvolta un sito
defacciato può contenere immagini o testo inquietanti, messaggi politici e così via.
5
6. I danni possono anche non essere così evidenti però. Un attaccante capace di
sostituire completamente i contenuti di un sito potrebbe anche eseguire modifiche
6
7. più difficile, se non impossibili, da rilevare da parte dei visitatori delle pagine web,
come ad esempio modificare uno script che raccoglie nomi utenti e password inviati
dagli utenti in modo che queste venga inviate in un posto scelto dall’attaccante.
3.2.1 TIPOLOGIE DI ATTACCHI
Un defacement può essere attuato in vari modi; tralasciando le tecniche che si
basano su operatori disonesti, si evidenziano di seguito alcune delle strade più
sfruttate, per le quali possiamo vedere nella seguente immagine le frequenze di
utilizzo stimate:
File inclusion
14%
2% FTP Server intrusion
27%
5%
Web Application bugs
8%
Attack against the
administrator
13%
9% Web Server intrusion
11% SQL Injection
11%
Figura 1 frequenza utilizzo metodi utilizzati per ottenere defacement. Fonte: VALUTAZIONE DI ALGORITMI DI ANOMALY DETECTION PER
LA RILEVAZIONE AUTOMATICA DELLE INTRUSIONI IN SITI WEB (G. Davanzo)
File inclusion (24%): si verifica quando uno script richiede come parametro il
nome di un file da includere nella sua esecuzione. Se non vengono previsti
adeguati controlli, un malintenzionato può indicare uno script appositamente
realizzato e residente su un altro server, ottenendo così la possibilità di
eseguire del codice direttamente sulla macchina attaccata.
FTP Server intrusion (12%): nonostante possa apparire come una tecnica
prevedibile, sfrutta il protocollo FTP per caricare materiale illecito all'interno di
server non protetti in maniera adeguata per esempio, accedendo a server per i
quali sono rimaste attive username e password di default.
7
8. Web Application bugs (10%): una buona fetta di responsabilità spetta alle
applicazioni scritte in malo modo, nelle quali si trascurano le più elementari
norme di sicurezza. Accade così che programmatori sbadati si dimentichino di
verificare le credenziali di accesso all'interno di tutte le pagine che dovrebbero
essere protette, oppure semplifichino i controlli di accesso al punto tale da
renderli inutili.
Attack against the administrator (10%): solitamente sfruttano il social
engineering per ottenere illecitamente username e password
dell'amministratore; più rari sono i casi in cui l'attaccante riesce a 'sniffare' il
traffico di rete del gestore del sistema e ottenere le password necessarie per
compiere il defacement.
Web Server intrusion (8%): si applica sfruttando gli errori di programmazione
esistenti all'interno delle applicazioni server, cercando solitamente di ottenere
privilegi superiori a quelli che effettivamente dovrebbero spettare.
SQL Injection (7%): molto simile al File inclusion utilizza predicati SQL per
compiere operazioni non lecite sul database. Per esempio, si ipotizzi una
verifica di credenziali basata sul fatto che la seguente query ritorni almeno una
SELECT * FROM tblUsers WHERE
tupla
password=passedPassword. E' però possibile che un utente
malintenzionato digiti come password del codice sql del tipo 'pippo' or
1=1 poiché la seconda condizione si verifica sempre, la query ritornerà tutte le
tuple del database e l'attaccante avrà libero accesso al sito attaccato.
Man in the Middle (4%): effettivamente è una strategia molto difficile da
attuare. Richiede infatti un discreto accesso alle risorse di rete della macchina
server o di chi vi si collega come amministratore, ma diventa banalmente
applicabile all'interno di grosse reti aziendali. Il Mani in the Middle è un
attacco nel quale l'attaccante è in grado di leggere, inserire o modificare a
piacere, messaggi tra due parti senza che nessuna delle due sia in grado di
sapere se il collegamento sia stato compromesso. L'attaccante deve essere
quindi in grado di osservare e intercettare il transito dei messaggi tra il sito e la
vittima.
DNS poisoning (2%): ancor più difficile del Man in the Middle, è comunque una
strada a volte percorribile; lo si effettua convincendo un DNS ad indirizzare i
richiedenti la pagina attaccata verso un indirizzo IP diverso da quello
lecitamente registrato. Per la definizione data tale operazione non è
8
9. propriamente un defacement, in accordo con quanto stabilito dagli stessi
gestori di Zone-H (i quali, comunque, tempo fa sono stati soggetti ad un
attacco di questo tipo).
3.3 STRUTTURA DEL PROGETTO
Il progetto complessivo è composto da tre parti ben distinte che interagiscono per
raggiungere lo scopo del progetto. Le tre parti sono:
1. NODO DI ELABORAZIONE
Il nodo di elaborazione, o istanza, come dice il nome è quella parte del
programma responsabile del monitoraggio vera e propria delle pagine web.
2. CONTROLLORE
Lo scopo del controllore è quello di coordinare il lavoro di uno o più nodi di
elaborazione ed avvisare i proprietari dei siti web dei defacement rilevati.
3. INTERFACCIA GRAFICA
L’interfaccia grafica permette agli utenti, essenzialmente i proprietari dei siti
web e gli amministratori di questo progetto, di controllare lo stato del
monitoraggio e di aggiungere nuovi siti da controllare.
Figura 2 Schema grafico della struttura del progetto
9
10. 3.4 COMPITI DEL NODO DI ELABORAZIONE
Partendo dai requisiti iniziali:
1. Ogni istanza funziona in modo del tutto autonomo, indipendentemente dalla
presenza o meno di altre istanze o di controllori.
2. Ogni istanza è controllabile esclusivamente in maniera programmatica.
3. Deve essere possibile creare nuove istanze rapidamente e con minimo
intervento di un operatore.
4. Deve essere possibile aggiornare il software di tutte le istanze rapidamente e
con minimo intervento di un operatore.
5. Ogni istanza mantiene dinamicamente due indici di carico, il cui significato
deve essere uniforme sulle diverse istanze e deve avere un significato relativo
alla potenza di calcolo e di memorizzazione dell'istanza stessa
cpuLoadIndex (esempio: 0.75 significa che l'istanza funziona al 75% delle
proprie capacità di calcolo)
storageLoadIndex (esempio: 0.75 significa che l'istanza ha consumato il
75% delle proprie capacità di memorizzazione)
6. Ogni istanza mantiene dinamicamente alcuni indici di prestazione, il cui
significato deve essere uniforme sulle diverse istanze e deve avere un
significato assoluto
fetchShortTermThroughput (esempio: 500 significa che l'istanza ha
prelevato nell'ultimo minuto circa 500 reading)
fetchLongTermThroughput (esempio: 50000 significa che l'istanza ha
prelevato nell'ultimo giorno circa 50000 reading)
globalReadings (esempio: 50000 significa che l'istanza ha prelevato 50000
reading da quando è stata inserita nel sistema)
databaseSize (esempio: 2.7 significa che l'istanza sta utilizzando 2.7 GB
della propria memoria secondaria)
si è cercato di ottenere un’architettura il più efficiente possibile senza essere troppo
complessa.
In definitiva il compito del nodo di elaborazione concretamente realizzato consiste
nello scaricare i dati dei siti, analizzarli e catalogarli e, nel caso di un defacement, vero
o sospettato, segnalare la condizione anomala alle altre componenti del progetto.
L’unità di lavoro del nodo di elaborazione è il task, questo rappresenta il
monitoraggio di una singola pagina web. Ogni task può essere configurato in maniera
indipendente dagli altri in modo da variare la frequenza con cui il programma
10
11. controlla la pagina web e che tipo di analisi effettuare. La segnalazione di condizioni
anomale avviene tramite gli “alert”, questi rappresentano una singola condizione
anomala e ne descrivono la causa; gli alert vengono poi utilizzati dal controllore per
avvertire, a secondo del problema verificatosi, o il proprietario del sito monitorato o
l’amministratore di questo progetto.
11
12. 4 - IMPLEMENTAZIONE DEL NODO DI ELABORAZIONE
4.1 TECNOLOGIE UTILIZZATE
Per sviluppare questo progetto sono state impiegate alcune tecnologie software per
facilitarne lo sviluppo; qui di seguito vengono elencate spiegandone l’utilità.
1. ENTERPRISE JAVA BEANS
Gli Enterprise Java Beans (EJB) sono una tecnologia standard che permette di
sviluppare la business logic di un programma delegando la responsabilità di
fornire alcune funzionalità comuni all’application server, cioè il programma
responsabile dell’esecuzione degli EJB. I servizi da noi utilizzati forniti
dall’application server sono la transazionalità, la gestione automatica della
concorrenza e l’invocazione di procedure remote.
2. JAVA PERSISTENCE API
La Java Persistence API (JPA) è un framework che permette la gestione dati su
un database relazionale tramite l’utilizzo di normali oggetti java. All’interno di
questo progetto JPA è stato utilizzato per il salvataggio di tutte le informazioni
necessarie all’analisi delle pagine Web
3. SHOAL
Shoal è un framework Java per la creazione di cluster, questo permette a più
istanze di comunicare tra loro in maniera automatizzata dati condivisi, e la
notifica dell’aggiunta o della rimozione di un altro nodo di elaborazione, tanto
per uno spegnimento voluto quanto per un guasto.
4. HTML PARSER
HTML Parser è una libreria Java in grado di eseguire il parsing di pagine html
per estrarne il contenuto. Anche se a prima vista l’html sembra uguale al più
rigoroso xml in realtà la sintassi dei due linguaggi è notevolmente diversa
soprattutto tenendo conto che un parser html deve anche gestire i numerosi
errori di sintassi presenti nella maggior parte delle pagine web.
Alcune di queste tecnologie sono implementate da più programmi diversi,
permettendo quindi una scelta tra alternative più o meno compatibili tra loro, le
nostre scelte sono state le seguenti:
12
13. 1. GLASSFISH 2
Questo programma è la reference implementation dello standard EJB e
fornisce anche il supporto a JPA tramite l’inclusione al suo interno di Toplink
Essentials
2. POSTGRESQL
Per il salvataggio vero e proprio dei dati è stato scelto l’utilizzo di questo
database relazionale, anche se, grazie all’uso di JPA, il codice dell’applicativo
sviluppato è del tutto indipendente dalla scelta del DBMS.
4.2 ANALISI DETTAGLIATA DEL NODO DI ELABORAZIONE
Qui di seguito viene riportata un’analisi dettagliata delle componenti principali del
nodo di elaborazione.
Fondamentalmente tutto il lavoro dell’istanza consiste nell’eseguire periodicamente i
singoli task assegnati all’istanza stessa. Ogni singola esecuzione di un task
corrisponde all’esecuzione di un algoritmo ben definito:
1. viene scaricata la pagina web corrispondente all’URL assegnato al task
corrente
2. vengono analizzate e poi scaricate le dipendenze della pagina iniziale,
ripetendo ricorsivamente questo processo per ogni pagina scaricata, fino ad un
livello massimo predefinito
3. vengono applicati alla pagina web i sensori, questi ultimi verranno descritti in
dettaglio in un paragrafo successivo
4. utilizzando i risultati dei sensori vengono rilevati gli eventuali defacement,
qualora se ne rilevino vengono generati degli avvisi per comunicare la
situazione
5. tutti i dati elaborati vengono salvati sul database.
Nel caso in cui il download di una o più pagine fallisca viene semplicemente generato
un avviso con i dettagli e l’elaborazione prosegue utilizzando i dati parziali.
Qualsiasi altro errore, in qualsiasi punto dell’algoritmo avvenga, viene gestito tramite
il supporto degli EJB alle transazioni, in pratica cioè in presenza di errori non gestiti
esplicitamente, teoricamente non dovrebbero mai verificarsi, tutta l’elaborazione
fatta viene annullata, riportando tutti i dati allo stesso stato che avevano prima di
iniziare l’elaborazione.
13
14. Un ulteriore condizione di errore gestita specificatamente è quella di crash di sistema
che può portare alla perdita di alcuni dati, tale situazione viene descritta in dettaglio
nella sezione 3.2.2
Nella pagina seguente viene riportato un diagramma UML che schematizza
l’algoritmo descritto.
Figura 3 Diagramma UML dell'algoritmo di elaborazione di un task
14
15. 4.2.1 ANALISI DI UNA PAGINA WEB
L’analisi di una pagina web viene effettuata tramite l’interazione di numerose classi
suddivise in tre categorie:
1. Sensori
2. Aggregatori
3. Feeder
Un sensore è un componente software atto ad analizzare uno specifico aspetto di una
pagina web e restituire un risultato in modo puramente funzionale, cioè privo di
stato; questa definizione molto ampia e generale permette ad un sensore di poter
svolgere praticamente qualsiasi tipo di analisi senza limitazioni. Un aspetto
estremamente importante dei sensori sono le dipendenze, infatti ogni sensore
dichiara una lista di sensori da cui dipende, intendendo con questo che i propri
ingressi, in aggiunta alla pagina web originale, consistono nelle uscite dei sensori da
cui essi stesso dipende. Questo permette di evitare la duplicazione inutile di codice,
infatti se due sensori diversi hanno una logica simile si può separare la parte comune
in un terzo sensore da cui i primi due dipendano.
Per semplificare le analisi statistiche necessarie a controllare gli eventuali defacement
è stato definita una famiglia particolare di sensori (sensori numerici) che deve
restituire come risultato delle analisi una lista di numeri; in concreto quindi i sensori
su cui vengono effettuate le analisi statistiche sono tutti di tipo numerico, e gli altri
sensori vengono solo utilizzati per fornire dati ai sensori numerici.
15
16. Figura 4 Schema delle classi relativa all'analisi delle pagine web
16
17. Un aggregatore, invece, è un componente software che, a partire dai risultati di un
certo numero di sensori numerici, crea un modello di una pagina web tramite il quale,
valutando l’andamento dei contenuti della pagina web monitorata nel tempo,
discrimina fra defacement e cambiamenti normali. Le operazioni che un aggregatore
può eseguire sono, quindi, due: valutare lo stato di una pagina e aggiornare il proprio
modello interno a partire da una nuova versione della pagina web.
L’ultimo componente necessario all’analisi di una pagina web è il feeder, questo è
responsabile di applicare i sensori alla pagina web e decidere se i risultati delle analisi
verranno utilizzati o meno per l’aggiornamento dello stato dell’aggregatore; per la
precisione dopo aver analizzato lo stato di una pagina web se questo è un sospetto
defacement non verrà mai utilizzato per aggiornare il modello dell’aggregatore, in
caso contrario verrà utilizzato solo se è passato più di un certo tempo dall’ultimo
aggiornamento.
Un’ultima funzione dei feeder è l’applicazione del feedback degli utenti. Poiché
nessun algoritmo può garantire in maniera assoluta il rilevamento di un defacement è
possibile che l’analisi di una pagina web provochi un falso positivo o, peggio ancora,
un falso negativo; in questo caso è possibile per l’utente fornire le correzioni
necessarie, il feedback appunto, per correggere gli errori. Nel caso di feedback
dell’utente lo scopo del feeder è quindi quello di riportare lo stato dell’aggregatore a
quello subito precedente all’errore, e poi aggiornarne nuovamente lo stato con le
nuove informazioni.
4.2.2 SCHEDULING DEI TASK
Come già detto in precedenza un task rappresenta il monitoraggio di una singola
pagina web e ne specifica il periodo di campionamento, pertanto ha bisogno di
un’infrastruttura che ne permette l’esecuzione in maniera periodica. Fortunatamente
la tecnologia EJB fornisce supporto all’infrastruttura degli EJB timer, questi
permettono l’esecuzione temporizzata di codice, garantendone l’esecuzione anche
dopo un crash di sistema.
Purtroppo però gli EJB timer non permettono da soli di associare uno stato
modificabile, nel nostro caso l’insieme del feeder e degli aggregatori, all’esecuzione
del codice del timer. Per aggirare tale problema si è salvato lo stato all’interno di uno
stateful EJB, questo tipo di componente software serve proprio a salvare uno stato
persistente nel tempo, sfortunatamente però uno stateful EJB non garantisce
l’accesso ai dati in seguito ad un crash di sistema, per ovviare a quest’ultimo
17
18. problema è stato creato del codice in grado di ricreare lo stato dell’aggregatore a
partire dai dati salvati sul database.
4.2.3 DOWNLOAD DI UNA PAGINA WEB
Prima di poter analizzare una pagina web bisogna ovviamente scaricarla sulla
macchina locale. Questa operazione, all’apparenza semplice, è in realtà abbastanza
complicata, in parte anche a causa dalle particolari necessità del programma. La
prima particolarità nel download di una pagina è la gestione manuale dei redirect;
normalmente quando si scarica una pagina web si delega la gestione dei redirect alla
libreria http utilizzata, ma nel nostro caso abbiamo dovuto gestirla a mano per poter
memorizzare sul database tutti i passaggi intermedi, in quanto potrebbero venir
scritti in futuro dei sensori che operano anche su queste informazioni. Per ogni passo
di redirezione, nella maggior parte dei casi ce n’è soltanto uno, bisogna inoltre
salvare tutti gli header http sia della richiesta che della risposta.
Un’altra particolarità nel codice di download delle pagine web è la gestione del
caching per minimizzare lo spreco di risorse, in particolare banda e spazio su disco;il
protocollo http fornisce infatti, nella sua versione 1.1, il supporto nativo al caching
tramite l’uso di una di due metodologie diverse. La prima metodologia consta
nell’uso delle data di ultima modifica di una particolare pagina web, infatti
aggiungendo un apposito header nella richiesta di una pagina si può richiedere al
server di inviare i dati solo se ci sono state modifiche posteriori a quella data. Il
secondo approccio si basa invece sugli “E-tag” questi sono degli identificatori generati
dal server web per marcare una particolare versione di una pagina web, ogni volta
che il contenuto di una pagina cambia, cambia anche l’E-Tag associato; aggiungendo
tra gli header della richiesta l’E-Tag dell’ultima versione scaricata di una pagina si
istruisce al server di restituire il contenuto solo se è stato variato.
Purtroppo molte pagine web, soprattutto quelle di tipo dinamico, non supportano
nessun tipo di caching obbligando quindi di riscaricare sempre e comunque l’intera
pagina, ma fortunatamente il supporto al caching per le immagini, di dimensioni
normalmente maggiori delle pagine web associate, è molto più diffuso.
L’ultima, e più complessa, peculiarità del downloader del progetto è quella di
ricostruire, a partire da una singola pagina web, l’albero delle dipendenze completo
della pagina stessa; per esempio praticamente ogni pagina web reale ha almeno
un’immagine visualizzata al suo interno ed utilizza un foglio CSS per definire la
formattazione. Per costruire l’albero delle dipendenze il programma analizza in
maniera ricorsiva la pagina iniziale e le dipendenze della stessa utilizzando una sere di
18
19. sensori creati all’uopo; inoltre per evitare ricorsioni infinite dovute a dipendenze
circolari l’applicazione utilizza una cache temporanea per vedere se la pagina da
aggiungere sia già stata analizzata ed impone una profondità massima dell’albero
delle dipendenze stesso.
Nella pagina seguente viene riportato lo schema completo di tutte le classi utilizzate
per salvare le pagine web.
19
21. 4.2.4 COMUNICAZIONE TRA NODO E CONTROLLORE
Poiché il nodo di elaborazione è sprovvisto sia di interfaccia grafica che di interfaccia
a linea di comando questo può venir comandato solo dal controllore tramite
l’invocazione di metodi remoti. L’invocazione di metodi remoti (remote procedure
call o RPC) è una tecnica che permette di eseguire del codice a distanza tra due
macchine diverse collegate tra loro da una rete, rendendo al contempo la differenza
tra chiamate locali e remote il minore possibile. In particolare nel nostro programma
questo è stato reso possibile tramite un particolare costrutto della tecnologia EJB
noto come remote stateless session bean.
Uno stateless session bean consiste in un’interfaccia java che definisce i metodi
richiamabili remotamente che deve essere condivisa tra chiamato e chiamante ed
una classe java nota solo al chiamato che implementa la suddetta interfaccia. Questo
tecnologia rende la differenza tra chiamate locali e remote estremamente ridotta,
consistente nel solo fatto che i parametri passati alla funzioni sono passati per valore
invece che per riferimento come di solito con gli oggetti Java; se però i dati passati
appartengono ad un tipo nativo di Java o ad un oggetto immutabile, come ad
esempio le stringhe, la differenza diventa nulla.
Qui di seguito viene riportata l’interfaccia utilizzata per la comunicazione tra nodo di
elaborazione e controllore.
package it.units.goldrake.common.ejb;
import it.units.goldrake.common.entities.SnapshotBase;
import it.units.goldrake.common.entities.DataChunkBase;
import it.units.goldrake.common.entities.InstanceAlertBase;
import it.units.goldrake.common.entities.NetworkAlertBase;
import it.units.goldrake.common.entities.ContentAlertBase;
import it.units.goldrake.common.entities.TaskDescriptorBase;
import it.units.goldrake.common.exceptions.*;
import java.net.URI;
import java.util.*;
import javax.ejb.Remote;
/**
* This interface exports all the operation relative to Task
* amministration
* of a Goldrake Instance
*/
@Remote
public interface InstanceRemote {
21
22. /**
* This method schedule a Task to be executed on this
* Instance
* @param descriptor A TaskDecriptor object that describes
* the task to be schedulated
* @throws it.units.goldrake.common.DuplicateTaskException
* If the task is already running
*/
void createTask(TaskDescriptorBase descriptor) throws
TaskException;
/**
* This method returns the TaskDesciptor describing the
* task with the specified ID
* @param taskId The ID of the TaskDescriptorBase to
* retrieve
* @return The task descriptor associated with given ID
* @throws it.units.goldrake.common.TaskNotFoundException
*/
TaskDescriptorBase getTaskDescriptor(long taskId) throws
TaskException;
/**
* This method returns the value of the specified property
* from the extendedProperties
* map of the task identified by the given id
* @param taskId the id of the wanted task
* @param propertyName the name of the properties to
* obtain
* @return the value of the property or null if it doesn't
* exits
* @throws
* it.units.goldrake.common.exceptions.TaskException when
* the given Id does not exist
*/
String getPropertyOfTask(long taskId, String propertyName)
throws TaskException;
/**
* This method set the value of the specified property
* from the extendedProperties
* map of the task identified by the given id
* @param taskId the id of the wanted task
* @param propertyName the name of the properties to set
* @param propertyValue the new value of the property, if
* it is null it deletes the property instead
* @throws
* it.units.goldrake.common.exceptions.TaskException
*/
void setPropertyOfTask(long taskId, String propertyName,
22
23. String propertyValue) throws TaskException;
/**
* This method terminates the execution of the selected
* Task
* @param taskId The ID of the Task to be terminated
* @throws it.units.goldrake.common.TaskNotFoundException
* If the task doesn't exist or is not active
*/
void terminateTask(long taskId) throws TaskException;
/**
* This method terminates the execution of the selected
* Task and save the identifier of the Instance that
* countinue this task
* @param taskId The ID of the Task to be terminated
* @param instance An URI that identifies the next
* instance
* @throws it.units.goldrake.common.TaskNotFoundException
* If the task doesn't exist or is not active
*/
void terminateTaskAndLinkTo(long taskId, URI instance)
throws TaskException;
/**
* This method set the identifier of the Instance that
* executed this Task previously
* @param taskId The ID of the Task to be linked
* @param instance An URI that identifies the previous
* instance
* @throws it.units.goldrake.common.TaskNotFoundException
* If the task doesn't exist or is not active
*/
void linkFrom(long taskId, URI instance)
throws TaskException;
/**
* This method return a list of DataChunkBase containing
* data about a specified Task
* @param taskId The ID of the Task of which retrieve the
* data
* @return A List<DataChunkBase> that contains the
* DataChunkBase
*/
List<DataChunkBase> getTaskDataChunks(long taskId);
23
24. /**
* This method returns the last SnapshotBase of a
* specified Task
* @param taskId The ID of the Task of which retrieve the
* data
* @param recursive if true the returned object contains
* all of its children.
* if false it contains only the children rappresenting
* its graphical rappresentation
* @return The last SnapshotBase taken by the specified
* task
*/
SnapshotBase getTaskLastSnapshot(long taskId,
boolean recursive) throws TaskException;
/**
* This method returns the last n SnapshotBase of a
* specified Task
* @param taskId The ID of the Task of which retrieve the
* data
* @param quantity How many SnapshotBase to retrieve
* @param recursive if true the returned objects contains
* all of their children.
* if false it contains only the children rappresenting
* their graphical rappresentation
* @return a list of SnapshotBase potentially empty
*/
List<SnapshotBase> getLastsSnapshotsOfTask(long taskId,
int quantity, boolean recursive);
/**
* This method return all the SnapshotBase taken in the
* specified day of the specified Task
* @param taskId The ID of the Task of which retrieve the
* data
* @param theDay the day of interest
* @param recursive if true the returned objects contains
* all of their children.
* if false it contains only the children rappresenting
* their graphical rappresentation
* @return a list of SnapshotBase potentially empty
*/
List<SnapshotBase> getSnapshotsOfTaskInDay(long taskId,
Date theDay, boolean recursive);
24
25. /**
* This method retrieve the SnapshotBase with the
* specified Id
* @param snapshotId The Id pf the SnapshotBase to retrive
* @param recursive if true the returned object contains
* all of its children.Iif false it contains only the
* children rappresenting its graphical rappresentation
* @return The wanted SnapshotBase
* @throws it.units.goldrake.common.TaskNotFoundException
* If the SnapshotBase does not exist
*/
SnapshotBase getSnapshotById(long snapshotId,
boolean recursive)
throws TaskNotFoundException;
/**
* This method return a list containing all the currently
* active tasks
* @return A list of the TaskDescriptorBase describing
* active tasks
*/
List<TaskDescriptorBase> getActiveTasks();
/**
* This method return a list containing all the currently
* active on-line tasks
* @return A list of the TaskDescriptorBase describing
* active on-line tasks
*/
List<TaskDescriptorBase> getActiveTasksOnLine();
/**
* This method return a list containing all the currently
* active simulated tasks
* @return A list of the TaskDescriptorBase describing
* active simulated tasks
*/
List<TaskDescriptorBase> getActiveTasksSimulated();
/**
* This method return a list containing all known tasks
* @return A list of the TaskDescriptorBase describing
* known tasks
*/
List<TaskDescriptorBase> getAllTasks();
25
26. /**
* This method returns all the InstanceAlertBase newer
* than the specified date
* @param startDate the initial date
* @return a list of InstanceAlertBase
*/
List<InstanceAlertBase> getInstanceAlerts(Date startDate);
/**
* This method returns all the ContentAlertBase newer than
* the specified date
* @param startDate the initial date
* @return a list of ContentAlertBase
*/
List<ContentAlertBase> getContentAlerts(Date startDate);
/**
* This method returns all the NetworkAlertBase newer than
* the specified date
* @param startDate the initial date
* @return a list of NetworkAlertBase
*/
List<NetworkAlertBase> getNetworkAlerts(Date startDate);
/**
* This method is meant to apply the user feedback to the
* aggregators of a task
* in case of false positive or false negative
* @param taskId the Id of the task that must be corrected
* @param corrections a list of SnapshotBase indicating
* the wanted outcomes. Only the Id and Outcome properties
* of the objects are evaluated, all other properties can
* be null
* @return a list of SnapshotBase whose Outcomes changed
* because of the corrections applied
*/
List<SnapshotBase> forceTaskOutcomes(long taskId,
List<SnapshotBase> corrections);
}
26
27. 4.2.5 PROPAGAZIONE DEGLI ALERT
Poiché ogni nodo di elaborazione non è in diretto contatto con gli utenti ha bisogno
di qualche modo per comunicare al controllore gli eventuali problemi riscontrati in
modo che questi possa poi comunicarli agli interessati; per risolvere questo problema
si è deciso di creare in ogni nodo di elaborazione una lista di avvisi, detti alert,
contenenti al loro interno la descrizione del problema. Gli alert si suddividono in tre
categorie: la categoria degli alert di contenuto (ContentAlert) serve a indicare un
possibile defacement, le informazioni che contiene sono il task che l’ha generato, la
specifica versione della pagina web (snapshot) interessata ed eventuali messaggi
degli aggregatori. La seconda categoria è invece quelle degli alert di rete
(NetworkAlert) che indica un qualche problema durante il download di una pagina
web come ad esempio l’impossibilità di trovare il server remoto od un qualche errore
dello stesso come ad esempio il noto errore http “File not found”; le informazioni
contenute in questo tipo di alert sono le stesse di un alert con la sola differenza che la
pagina web potrebbe essere assente del tutto.
L’ultima categoria di alert è invece quella degli alert di istanza (InstanceAlert), questi
rappresentano un errore causato dal nodo di elaborazione stesso. L’unico
InstanceAlert generato attualmente è quello che corrisponde alla mancata
esecuzione di un’analisi di una pagina web causato da un sovraccarico del nodo
stesso; al contrario degli altri alert questo contiene al suo interno solo l’identificativo
del nodo che lo ha generato ed un messaggio di errore che ne spiega la causa.
Gli alert sono accessibili dal controllore tramite tre metodi remoti, uno per categoria
di avvisi, i quali, per evitare di sprecare banda inutilmente, accettano come
parametro di ingresso una data che rappresenta la data dell’ultimo avviso noto al
controllore permettendo quindi, in caso non ci siano nuovi avvisi, di non inviare dati
inutilmente.
4.2.6 INDICI DI CARICO
Poiché alla creazione di un task il controllore deve decidere su quale nodo di
elaborazione deve avviare il lavoro questo ha bisogna di una metodologia per la
scelta del nodo. A questo scopo sono stati creati li indici di carico; questi sono degli
indicatori numerici delle risorse hardware, come ad esempi la percentuale di
processore utilizzato o lo spazio libero su disco, attualmente utilizzate su un
determinato nodo di elaborazione. Grazie agli indici di carico è possibile decidere non
solo di avviare nuovi task sulla macchina meno occupata ma anche di rilevare
eventuali sovraccarichi e spostare l’esecuzione dei task da una macchina sovraccarica
27
28. ad una meno impegnata. Come gli alert anche gli indici di carico sono acceduti dal
controllore tramite l’uso di metodi remoti.
4.2.7 CLUSTERING DEI NODI DI ELABORAZIONE
Per semplificare l’utilizzo simultaneo di più nodi di elaborazione in una stessa rete
locale si è deciso di avvalersi di una libreria di clustering per automatizzare alcune
funzioni in modo da diminuire il più possibile la configurazione da eseguire
manualmente in questo contesto. Per raggiungere questo scopo si è introdotto il
concetto di gruppo di istanze, questo rappresenta un’insieme di due o più nodi di
elaborazione fisicamente collocate nella stessa rete, all’interno di un gruppo
l’aggiunta o la rimozione di un nodo viene rilevata automaticamente da tutti gli altri
nodi tramite delle notifiche da parte della libreria di clustering. Altre due funzionalità
ottenute dall’uso del clustering sono la rilevazione automatica di guasti di un nodo e
la condivisione tra tutti i nodi di un gruppo degli indici di carico.
Grazie a questa infrastruttura il controllore può automaticamente trovare tutti i nodi
di un gruppo conoscendo semplicemente l’indirizzo di uno di questi nodi e, tramite
l’invocazione di metodi remoti, ottenere automaticamente la lista di tutte le istanza
del gruppo, inoltre anche l’accesso agli indici di carico è semplificato in quanto basta
richiederli ad uno qualsiasi dei nodi di un gruppo.
Qui di seguito è riportata l’interfaccia remota che permette di ottenere la lista dei
nodi di un gruppo e gli indici di carico dello stesso.
28
29. package it.units.goldrake.common.ejb;
import it.units.goldrake.common.entities.Instance;
import it.units.goldrake.common.entities.LoadIndexType;
import java.io.Serializable;
import java.net.URI;
import java.util.List;
import java.util.Map;
import javax.ejb.Remote;
/**
* This interface exports all the operation relative to group
* administration and load index of a Goldrake Instance
*/
@Remote
public interface InstanceManagementRemote {
/**
* This method return a list of all instances known to
* this instance, if this instance doesn't belong to a
* group or if the group doesn't contains other instances
* the list returned contains only reference to this
* instance.
* @return a list of known instances
*/
List<Instance> getInstancesList();
/**
* This method returns all the known load index of the
* specified instance, if this instance doesn't know any
* data about the specified instance the returned map is
* empty
* @param instanceURI The URI of the intance to obtain
* data about
* @return a map containing the load indexes of a instance,
* potentially empty
*/
Map<LoadIndexType,Serializable> getInstanceDetails(
URI instanceURI);
/**
* This method returns all the known load index of all the
* known instances, if this instance doesn't belong to a
* group or if the group doesn't contains other instances
* this method returns only the index of the current
* instance
* @return a map of load index keyed by the URI of the
* instance
*/
Map<URI, Map<LoadIndexType, Serializable>>
getAllDetails();}
29
30. 5 - CONCLUSIONI
5.1 OBBIETTIVI RAGGIUNTI
Il lavoro svolto fino a questo momento ha seguito essenzialmente i requisiti e le
specifiche formulate all’inizio, quanto elaborato riesce pertanto a monitorare i siti
web per rilevare in maniera automatica eventuali defacement.
5.2 PRINCIPALI PROBLEMI REALIZZATIVI
Durante la scrittura del programma sono state però effettuate alcune piccole
variazione ed aggiunte rispetto a quanto previsto, mentre altre parti inizialmente
pianificate saranno effettuate in un secondo momento.
5.2.1 CLUSTERING DI GLASSFISH
Vi sono state delle difficoltà tecniche nella parte riguardante il clustering;
inizialmente si pensava di sfruttare il supporto nativo di GlassFish al clustering, ma
dopo un esame più attento si è scoperto che non operava nel modo da noi voluto:
praticamente il clustering nativo creava una singola macchina logica corrispondente
ad un intero cluster, senza esternare la reale suddivisione del lavoro, non solo,
imponeva anche l’utilizzo di un solo database per l’intero cluster, mentre si preferiva,
per motivi di scalabilità, di avere un database indipendente per ogni istanza. Per tali
motivi si è deciso, come già accennato in precedenza, di ricorrere all’utilizzo diretto
della libreria Shoal utilizzata anche dal clustering di GlassFish.
L’utilizzo di questa libreria ha però portato un altro problema, infatti GlassFish, in
caso di comunicazione tra due server appartenenti allo stesso cluster, abilita
automaticamente l’uso di transazioni distribuite, le quali risultano
computazionalmente molto pesanti, e richiedono l’utilizzo di driver particolari per
l’accesso ai database. La soluzione effettuata è stata quella, già descritta
precedentemente, di escludere il controllore dal cluster, in quanto, come da requisiti,
le istanza non comunicano mai tra di loro.
Inoltre è stato sviluppato il supporto a più cluster separati ed a istanze singole non
appartenenti a nessun cluster, questa modifica permette una maggior scalabilità del
programma, in quanto l’elaborazione può essere suddivisa tra più reti distinte tra loro
e permette anche l’utilizzo di singole macchine noleggiate.
30
31. 5.2.2 SEPARAZIONE TRA INTERFACCIA GRAFICA E CONTROLLORE
Un’altra modifica rispetto ai piani iniziali riguarda una maggior divisione tra
interfaccia grafica e controllore; inizialmente il controllore poteva essere comandato
solo dall’interfaccia grafica, ma si è deciso, per semplificare l’amministrazione del
programma, di permettere ad altri programmi (nello specifico un programma a riga di
comando) di accedere alle funzionalità offerte dal controllore. Questa variazione si è
ottenuta trasformando l’interfaccia utilizzata dall’amministrazione web in una serie di
remote stateless session bean così da permettere l’esecuzione di codice remoto.
5.2.3 UTILIZZO DEI TIMER
Un ulteriore differenza è stato l’uso dei timer al posto dei message bean per la
schedulazione dei task, questa variazione è dovuta solo ad una maggior semplicità
d’uso, in quanto ci sarebbe stata comunque la necessità di impiegare almeno un
timer per schedulare l’invio dei messaggi.
5.2.4 FUNZIONALITÀ RIMANDATE
Vi sono state infine alcune funzionalità rimandate ad uno sviluppo futuro, nello
specifico è stata implementata solo la gestione degli utenti clienti (funzionalità
riguardante solo l’interfaccia grafica), mentre la gestione dei task simulati è stata
omessa completamente.
5.3 OSSERVAZIONI PERSONALI
Personalmente ritengo questo programma molto interessante e soprattutto attuale;
dal punto di vista dello sviluppo si potrebbero provare delle alternative a GlassFish, in
quanto quest’ultimo non si rivelato sempre affidabile, talvolta bloccandosi o
riportando errori casuali non riproducibili che scompaiono dopo il riavvio del server.
Sarebbe inoltre interessante cercare se esiste un metodo per mantenere l’attuale
separazione di codice tra le varie componenti (istanza e controllore) riducendo al
contempo la quantità di codice necessario da scrivere; infatti per ogni entità logica
condivisa tra controllore e istanza è stato necessario scrivere un’interfaccia e tre
classi i cui codici sono per la maggior parte identici senza poter sfruttare inoltre le
funzionalità di casting in quanto questi tipi non ereditano l’uno dall’altro.
31
32. 5.4 RINGRAZIAMENTI
Si ringrazia sentitamente per i consigli e la continua assistenza tecnica e umana il
relatore professor A. Bartoli e il correlatore prof. E. Medvet; si ringrazia anche il
dottor G. Davanzo per la sua collaborazione. Un sentito grazie anche agli altri tesisti
(dott. E. Sorio e dott. A. Zorzin) per la pazienza e la collaborazione necessaria per un
lavoro di gruppo come questo.
32
33. A - DOCUMENTO INIZIALE REQUISITI E SPECIFICHE DEL PROGETTO
A.1 REQUISITI GOLDRAKE
Cioè: cosa vogliamo che faccia, non come.
A.1.1 DEFINIZIONI
Risorsa: pagina web visualizzabile in un browser. Ogni risorsa è associata an
URL. Nel caso la risorsa sia un documento HTML, essa include anche tutte le
informazioni necessarie al browser per la sua visualizzazione (immagini,
javascript, CSS etc).
Warden: unità di servizio acquistabile dai clienti del sistema.
WardenProfile: elementi che definiscono la QoS del Warden. Ogni Warden ha
esattamente un WardenProfile e questo è immutabile.
Task: processo di monitoraggio di una risorsa. Ogni Task appartiene
esattamente ad un Warden.
Reading: immagine di una risorsa ad un dato istante.
Aggregator: algoritmo per catalogare i reading in normali o anomali.
A.1.2 GENERALE
1. Non deve essere legato ad alcun sistema operativo.
2. Deve essere possibile analizzare i Task anche dopo la loro terminazione ed
indipendentemente dalla versione del software utilizzato. In particolare, se la
rappresentazione interna di un Task include informazioni il cui formato
dipende dalla versione del software (ad esempio, oggetti Java serializzati quali
sensor e aggregator) queste informazioni devono essere utilizzabili in ogni
versione del sistema.
3. Consiste di:
una o più istanze, tipicamente molte più di una.
un controllore.
Ogni istanza effettua il monitoraggio di un insieme di risorse, il controllore (o
controllori) coordinano il sistema.
33
34. A.1.3 SCALABILITA'
1. Istanze: Alcune centinaia.
2. Risorse: Migliaia o poche decine di migliaia per istanza, in dipendenza della
potenza dell'istanza.
3. Warden: Migliaia
A.1.4 ISTANZE
1. Ogni istanza funziona in modo del tutto autonomo, indipendentemente dalla
presenza o meno di altre istanze o di controllori.
2. Ogni istanza è controllabile esclusivamente in maniera programmatica.
3. Deve essere possibile creare nuove istanze rapidamente e con minimo
intervento di un operatore.
4. Deve essere possibile aggiornare il software di tutte le istanze rapidamente e
con minimo intervento di un operatore.
5. Ogni istanza mantiene dinamicamente due indici di carico, il cui significato
deve essere uniforme sulle diverse istanze e deve avere un significato relativo
alla potenza di calcolo e di memorizzazione dell'istanza stessa
cpuLoadIndex (esempio: 0.75 significa che l'istanza funziona al 75% delle
proprie capacità di calcolo)
storageLoadIndex (esempio: 0.75 significa che l'istanza ha consumato il
75% delle proprie capacità di memorizzazione)
6. Ogni istanza mantiene dinamicamente alcuni indici di prestazione, il cui
significato deve essere uniforme sulle diverse istanze e deve avere un
significato assoluto
fetchShortTermThroughput (esempio: 500 significa che l'istanza ha
prelevato nell'ultimo minuto circa 500 reading)
fetchLongTermThroughput (esempio: 50000 significa che l'istanza ha
prelevato nell'ultimo giorno circa 50000 reading)
globalReadings (esempio: 50000 significa che l'istanza ha prelevato 50000
reading da quando è stata inserita nel sistema)
databaseSize (esempio: 2.7 significa che l'istanza sta utilizzando 2.7 GB
della propria memoria secondaria)
...
34
35. A.1.5 CONTROLLORE
1. Il controllore costituisce l'unica modalità di interazione con il sistema per gli
utenti.
2. Il controllore consiste di due moduli:
interfaccia grafica, accessibile agli utenti;
core, accessibile esclusivamente in maniera programmatica dall'interfaccia
grafica
3. Gli utenti interagiscono con l'interfaccia grafica. Questa interagisce con il core.
Questo interagisce con le istanze. L'interfaccia grafica non deve accedere alle
istanze bypassando il core.
4. Il controllore implementa la nozione di WardenProfile, che è del tutto
sconosciuta alle istanze.
5. Il controllore deve visualizzare l'elenco delle istanze esistenti e di quelle
attualmente attive.
6. Per ogni istanza, il controllore deve acquisire automaticamente le seguenti
informazioni:
variazioni attiva/inattiva, ritardo contenuto entro pochissimi minuti.
cpuLoadIndex, ritardo contenuto entro pochissimi minuti.
storageLoadIndex, ritardo contenuto entro qualche ora. (nota: sono
acquisiti automaticamente solo gli indici di carico, non gli indici di
prestazione).
instance alert, ritardo contenuto entro qualche ora
A.1.6 UTENTI
1. Sono divisi in tre categorie disgiunte:
Amministratori (operatori di Goldrake).
Amministratori Clienti (AC)
Utenti Clienti (UC)
2. Un AC può essere associato a più Warden, ognuno con il proprio
WardenProfile. Il controllore deve associare costantemente un AC al Warden
che sta impersonando.
3. I diritti delle categorie sono i seguenti:
Un Amministratore può operare su ogni risorsa; può aggiungere/rimuovere
AC; può aggiungere/rimuovere UC (associati ad un UC).
Un AC può operare su tutte le risorse del/dei warden corrispondenti; può
aggiungere/rimuovere suoi UC.
35
36. Un UC può operare solo sulle risorse che sono state da lui inserite nel
sistema.
A.1.7 TASK
1. Un task consiste di un descrittore e dati, come segue:
descrittore:
o id del Warden a cui appartiene il Task,
o URL della risorsa,
o samplingPeriod,
o startingTime, endingTime (possibly NULL),
o status: inProgress/completed, (descrive se il task è ancora in corso
oppure no)
o type: onLine/simulated, (descrive se il monitoraggio avviene in
tempo reale sulla risorsa reale oppure su un archivio raccolto in
precedenza; vedi i task simulati più sotto)
o setOfAggregators.
dati:
o sequenza di reading della risorsa. Ogni reading contiene:
informazioni necessarie per visualizzare completamente la
risorsa in un browser (immagini, javascript, CSS etc.) ;
istante a cui è stato prelevato il reading;
HTTP response ottenuta per ogni HTTP request utilizzata per
prelevare il reading.
per ogni aggregator del setOfAggregators,
outcome: normal/anomalous;
eventuale feedback (vedi più sotto il feedback di
utenti; occorre indicare se l'outcome è stata alterata
da un utente oppure no).
values of sensorList
o sequenza di alert generati, come segue:
per ogni aggregator del setOfAggregators
link ad ogni reading per il quale è stato generato un
content alert
descrizione dell'alert
link ad ogni reading per il quale è stato generato un
network alert
descrizione dell'alert
36
37. 2. Gli attributi di un task sono immutabili. Qualora sorgesse la necessità di variare
alcuni attributi di un task (ad esempio il samplingPeriod oppure il
setOfAggregators), allora occorre terminare il task e crearne un altro con i
valori opportuni per gli attributi. Operazioni del genere possono essere
facilitate dall'interfaccia grafica del controllore.
3. Le operazioni su un task sono:
a. creazione.
Può essere invocata da un A, AC, UC.
input: URL da monitorare, samplingPeriod, setOfAggregators
samplingPeriod può essere variato tra estremi prefissati in
base al WardenProfile
setOfAggregators contiene elementi fissati dal
WardenProfile. Alcuni WardenProfile possono permettere
all'utente che crea il task di includere zero o più
aggregator predefiniti della forma quot;sufficient conditionquot;.
Alcuni WardenProfile, disponibili solo agli Amministratori,
possono permettere all'utente che crea il task di scegliere
a proprio piacimento gli aggregator da inserire nel
setOfAggregators.
Il task appartiene al Warden associato all'utente che ha creato il
task.
L'istanza su cui eseguire il task è scelta automaticamente dal
controllore (in base a politiche al momento non specificate, che
si basano sugli indicatori di carico e sul WardenProfile).
E' possibile effettuare una creazione in batch di un insieme di
task: l'utente specifica il link di partenza ed un insieme di criteri
di ammissione da passare ad un crawler; al termine del crawl,
sarà fornito l'elenco delle risorse individuate e sarà possibile
creare automaticamente un task per ognuna di esse,
eventualmente eliminandone alcune manualmente.
b. terminazione
può essere invocata da un A, AC, UC.
c. checkpoint
può essere invocata da un A, AC, UC.
termina il task e ne crea un altro del tutto identico al precedente.
Può servire per contenere le dimensioni dei dati e per facilitare
l'esecuzione di task simulati.
37
38. d. modifica
può essere invocata da un A, AC, UC.
termina il task e ne crea un altro del tutto identico al precedente,
permettendo di modificare alcuni attributi selezionati.
e. migrazione per prestazioni
può essere invocata solo da un A.
Un task può essere forzato a migrare su un'altra istanza quando il
cpuLoadIndex dell'istanza su cui risiede il task diventa
quot;eccessivoquot;. La decisione su quando effettuare una migrazione e
verso quale istanza viene presa dal controllore (non dalle
istanze). Ciò può avvenire manualmente, su decisione
dell'operatore, oppure automaticamente.
f. migrazione per fault-tolerance
può essere invocata solo da un A.
Un task può essere forzato a migrare su un'altra istanza quando
l'istanza su cui risiede si guasta.
TASK SIMULATI
1. Un task può essere simulato. Un task simulato è associato a un altro task non
simulato e terminato. Un task simulato valuta il comportamento di uno o più
aggregator sui dati (sequenza di reading) già raccolti dal task associato.
2. Le operazioni possibli su un task simulato sono le stesse di quelle possibili su
un task non simulato. L'unica differenza tra i due è che un task simulato non
genera alert.
3. La creazione di task simulati è permessa solo ad alcuni WardenProfile.
A.1.8 AGGREGATOR
1. Un aggregator consiste delle seguenti informazioni:
Nome
ClasseCheImplementaAlgoritmo
VersioneAlgoritmo
EventualiParametri
SensorList
unique-ID
2. Un Aggregator riceve un array di numeri prodotti dalla rispettiva SensorList e
produce un valore di tipo enumerato: Normal, Anomalous, Learning.
38
39. 3. Un Aggregator può essere aggiunto o rimosso solo da un Amministratore. La
rimozione di un Aggregator implica che non sarà più possibile creare Task che
utilizzano quell'AggregatorModel. Sarà però possibile continuare ad utilizzare
le informazioni storiche associate ad eventuali Task che hanno usato
l'Aggregator rimosso.
A.1.9 ALERT
1. Un'istanza può generare varie tipologie di alert:
content alert, corrispondente ad un reading catalogato come anomalo da
un aggregator
network alert, corrispondente ad un reading il cui prelievo ha generato una
condizione di errore (network error, HTTP response con errore, numero
elevato di network error consecutivi...)
instance alert, corrispondente a situazioni anomale relative al
funzionamento dell'istanza nel suo complesso (indici di carico che superano
una soglia predefinita, ...)
2. Un'istanza genera alert per un reading r non appena si verifica una delle
condizioni seguenti:
content alert, quando l'output dell'aggregator applicato ad r è Anomalous e
l'output sul reading precedente non era Anomalous
network alert, quando il prelievo di r ha generato una condizione di errore
ed il prelievo del reading precedente non ha generato una condizione di
errore
instance alert, quando l'istanza rileva la situazione anomala.
3. Content alert e network alert sono associati al Task che ha causato il prelievo
del reading corrispondente. Instance alert non sono associati a nessun Task.
ALERT E UTENTI
1. Gli alert sono visibili agli utenti come segue:
content alert e network alert: agli A ed agli AC/UC che possono accedere al
Task
instance alert, solo agli A
2. Un utente può effettuare operazioni di subscribe / unsubscribe per gli alert
che può vedere. L'utente sceglie il metodo di trasmissione dell'alert tra quelli
disponibili nel proprio WardenProfile. Alcuni WardenProfile devono
supportare l'invio di alert agli utenti tramite email, SMS.
39
40. 3. Un alert deve contenere informazioni esplicative sulla natura dell'alert
(network alert e instance alert sono indipendenti dagli aggregator e dalla
sensorList, mentre i content alert non lo sono).
4. Il controllore deve:
acquisire un alert entro pochissimi minuti dalla sua generazione.
inviare ad ogni utente gli alert di sua pertinenza entro pochissimi minuti
dalla loro generazione
5. Ogni utente deve quot;vederequot; ogni alert di sua pertinenza. L'interfaccia grafica
mantiene evidenza, per ogni utente, degli alert inviati all'utente e non ancora
visti. Ciò avviene in modo analogo ai messaggi mail letti/non letti dei comuni
programmi mail client.
FEEDBACK DI UTENTI
1. Un utente può modificare la catalogazione di una sequenza di reading anomali
fornita da un aggregator. Ciò può avvenire solo in questo caso:
l'utente si collega all'interfaccia grafica all'istante t_0;
il reading più recente disponibile sull'interfaccia è relativo a un istante
quot;molto vicinoquot; a t_0;
questo reading è anomalo. In questo caso l'utente può decidere di
catalogare come normale il reading. Se i reading immediatamente
precedenti sono anch'essi anomali (sequenza di reading anomali che non
contiene reading normali) allora l'utente può catalogare come normali tutti
i reading della sequenza.
2. Questo feedback sarà utilizzato dall'aggregator corrispondente per modificare
il proprio stato interno di di conseguenza.
3. Il feedback fornito dagli utenti deve essere memorizzato nel Task
corrispondente.
A.1.10 INTERFACCIA GRAFICA
Deve offrire le seguenti view:
1. Amministrativa (accessibile solo agli A)
Gestione Utenti
Gestione Warden
Gestione WardenProfile
Gestione Istanze
40
41. o Elenco delle istanze esistenti, con evidenziazione grafica di quelle
attualmente attive.
o Elenco storico per una o più istanze, con possibilità di variare la
window temporale:
attività/inattività
indici di carico, indici di prestazioni
o Analisi di dettaglio dei log di un'istanza specificata, con possibilità di
variare la window temporale.
Gestione Alert
o Funzionalità analoghe alla view Alert (più sotto), con in più elenchi:
Globale
Per istanza
2. Alert
Numero degli alert quot;recentiquot;, con possibilità di variare la window
temporale, con possibilità di separare content/network:
o per warden
o per task
Analisi di dettaglio di singolo alert, con possibilità di
o visualizzazione contemporanea della view Reading per il reading
associato.
o feedback sui reading anomali (vedi alert, feedback)
3. Warden
Elenco degli warden, con ricerca per nome (tramite auto-completion)
Analisi di dettaglio del singolo warden (profile).
4. Task (di un warden selezionato, di più warden selezionati, di tutti i warden
accessibili all'utente)
Elenco dei task, con ricerca per URL (tramite auto-completion)
Come sopra, ristretto ai soli task con alert quot;non ancora vistiquot;
Analisi di dettaglio del task selezionato, con storico dei dati, con possibilità
di passaggio alla view Reading.
Operazioni sui task, come specificate più sopra.
5. Task simulati
come sopra, ristretto ai soli task simulati
6. Reading
Sequenza quot;navigabilequot; di reading, a partire da un reading specificato
Possibilità di evidenziare l'output degli aggregator associati al Task a cui
appartiene il reading (uno o più aggregator selezionati)
Possibilità di passare all'analisi di dettaglio del singolo alert
41
42. Per ogni reading deve essere facilmente accessibile:
o contenuto visibile su browser
o sorgente HTML/Javascript.... di ogni singolo elemento che compone
lo reading della risorsa
o risposte HTTP corrispondenti
o immagine del contenuto visibile su browser
risposte HTTP corrispondenti
In tutte le view (ad eccezione della view Amministrativa) deve essere chiaramente
evidenziato il Warden ed il Task nel contesto dei quali l'utente sta operando.
42
43. A.2 SPECIFICHE (PARZIALI) GOLDRAKE
Cioè: come vogliamo che siano implementati i requisiti
GENERALI
1. Java EE, GlassFish application server
2. Le istanze fanno parte di un cluster GlassFish. La membership (istanze attive) è
gestita dal GlassFish clustering. La propagazione degli indici di carico è gestita
dalla distributed cache del GlassFish clustering (da verificare).
3. Il core del controllore è membro del GlassFish cluster (in modo da poter
accedere agli indici di carico; per i soli fini della membership potrebbe essere
un client del membership service del cluster e non essere membro del cluster).
4. Controllore:
a. L'interfaccia grafica è scritta in JSF.
b. Il core consiste di un insieme di bean accessibili al codice dell'interfaccia
grafica
5. Ogni istanza accetta richieste attraverso stateless bean
6. L'accesso ai DB deve avvenire attraverso la persistence API (JPA), sia sulle
istanze sia sul core.
7. Ogni istanza opera esclusivamente da server. In particolare, ciò implica che:
una istanza non può invocare operazioni di altre istanze.
una istanza non può invocare operazioni sul controllore.
8. Tutti i messaggi di interazione con gli utenti devono essere in inglese.
A.2.1 DB CONTROLLORE
PREMESSA IMPORTANTE
Il DB del controllore deve contenere informazioni sulle entità non note alle istanze:
Warden, WardenProfile, Utenti. In linea teorica sarebbe possibile non memorizzare
alcuna informazione sui Task nel DB del controllore. Basterebbe memorizzare i Task
solo sulle istanze ed associare ad ogni Task un identificativo del Warden a cui
appartiene. Questo approccio però non è accettabile:
Alcune informazioni devono essere disponibili agli utenti anche in momenti di
temporanea inaccessibilità di alcune istanze (non è pensabile che un AC/UC
effettui un login e non veda l'elenco di tutti i suoi Task; è tollerabile che parti
dell'archivio siano temporaneamente indisponibili, ma almeno l'elenco delle
risorse che il Warden sta monitorando deve essere sempre disponibile).
43
44. Alcune informazioni devono essere ottenibili dall'interfaccia grafica
rapidamente (non è pensabile fare uno scan di tutte le istanze per scoprire
quali siano i Task di un dato Warden).
Il controllo degli accessi deve essere centralizzato (pertanto il controllore deve
avere l'elenco completo dei task, poiché la granularità del controllo è il task;
ciò implica che occorre mantenere sul DB del controllore una Tabella Task con
almeno 1 M record, poiché 100 istanze per 10000 task per istanza fa 1 M.)
Occorre pertanto memorizzare sul DB del controllore alcune informazioni relative ad
ogni singolo Task. Ciò introduce due problemi molto importanti:
Scalabilità (occorre mantenere sul DB del controllore una Tabella Task con
almeno 1 M record, poiché 100 istanze per 10000 task per istanza fa 1 M)
Coerenza tra i DB (ogni operazione di modifica a un Task, invocata dal
controllore, deve aggiornare in modo atomico il DB del controllore ed il DB
dell'istanza coinvolta. Guasti o malfunzionamenti durante l'esecuzione
dell'operazione possono introdurre incoerenze tra il DB del controllore e il DB
dell'istanza; inoltre, l'utente che provocato la modifica non conosce l'esito
dell'operazione).
Il problema di Scalabilità si risolve minimizzando la quantità di informazioni relative
ad un Task che sono mantenute nel DB del controllore.
Il problema di Coerenza tra i DB si potrebbe risolvere incapsulando ogni operazione di
modifica ad un Task in una transazione distribuita. Anche prescindendo dal costo in
termini di prestazioni, questo approccio non è accettabile:
Complessità:
o la gestione dei commit distribuiti è molto complicata ed è impensabile
programmarla esplicitamente;
o Java EE supporta automaticamente le transazioni centralizzate (un solo
DB) ma non quelle distribuite (più DB).
o Esistono application server con estensioni in grado di gestire transazioni
distribuite, ma sono di solito a pagamento e normalmente molto
complessi
o Il sistema dovrà essere programmato e gestito anche da persone che
possono non avere familiarità con le sottigliezze della fault-tolerance in
ambito distribuito, per cui è bene evitare queste problematiche.
Inoltre, l'uso delle transazioni atomiche distribuite non previene le incoerenze
tra i DB e non risolve l'incertezza dell'utente in caso di guasto. Questo
44
45. approccio garantisce solo che quando il guasto viene risolto, il sistema
automaticamente riporta i due DB nello stesso stato (tra l'altro, è anche
possibile che sino a quando non si risolve il guasto su uno dei due lati, la riga
del Task su cui si stava operando rimanga inutilizzabile sull'altro lato).
Il problema di Coerenza tra i DB si risolve come segue:
Le operazioni sui Task sono creazione, terminazione, migrazione, feedback di
utente
Ogni operazione di modifica dei Task deve essere implementata sul lato
controllore in questo modo:
o Invocazione operazione su Istanza
o Se OK, aggiornamento DB del controllore
o Se non-OK, notifica all'utente quot;non so se l'operazione è stata eseguita,
please try again laterquot;
Periodicamente, un repair thread sul controllore analizza in modo asincrono il
DB del controllore e il DB di ogni istanza (un'istanza ogni qualche ora, ad
esempio)
o when esiste task T su istanza A e non esiste su controllore: genera
notifica per gli amministratori (errore durante la creazione; in questo
caso la cosa più sensata è cancellare il task sull'istanza);
o when esiste task T terminato su istanza A e il controllore ritiene che T
stia su A ma non sia terminato (errore durante la terminazione; la cosa
più sensata è cancellare il task);
o when esiste task T su istanza A e il controllore ritiene che T stia su B:
esegue repair della migrazione (errore durante la migrazione; vedi note
realizzative più sotto);
In altre parole, prima si aggiorna l'istanza e poi si aggiorna il controllore. Le
incoerenze possibili si risolvono caso per caso, quando ci sono, visto che sono
semplici da rilevare, interpretare, gestire.
TABELLE
Schema da definire in maggiore dettaglio
Tabella degli Utenti
Tabella degli WardenProfile
Tabella degli Warden (l'unica informazione sui Task del Warden è il task_id;
nessuna informazione su quali istanze sono coinvolte)
Tabella dei Task
45
46. o task id
o URL
o ID dell'istanza contenente l'ultimo chunk (o uno quot;vicino all'ultimoquot;)
o info di ACL
o data dell'ultimo network alert ricevuto per questo Task
o data dell'ultimo content alert ricevuto per questo Task
Tabella degli Instance Alert
o instance id
o data dell'ultimo instance alert ricevuto da questa istanza
Da notare che gli alert risiedono sui DB delle istanze. Sul DB del controllore ci sono
solo le informazioni necessarie per sincronizzare controllore e istanze, per
permettere cioè al controllore di prelevare dalle istanze solo gli alert ancora non
prelevati (ricordare che le istanze non possono contattare il controllore ma sono
contattate da quest'ultimo, ad istanti fissati dall'interfaccia grafica).
A.2.2 CONTROLLORE
BREVE NOTA REALIZZATIVA SULL'INTERFACCIA GRAFICA
1. Il controllore può mostrare l'elenco dei Task, comprendente il solo URL,
rapidamente in quanto è disponibile nel DB locale.
2. Ogni altra informazione è prelevata dall'istanza. Per quot;ogni altra informazionequot;
si intende il descrittore del task, i reading, gli alert etc.
3. Queste informazioni sono inserite nella sessione HTTP dell'utente non appena
sono state prelevate, in modo da essere richiamate in seguito.
4. Pertanto, ogni volta che è necessario quot;prelevarequot; informazioni da una istanza,
prima si verifica se sono nella sessione HTTP; se non ci sono, si prelevano e si
inseriscono
RAPPRESENTAZIONE
1. Un task consiste di un descrittore e dati (vedi requisiti).
2. La migrazione di un task consiste nella migrazione del solo descrittore sulla
nuova istanza. I dati rimangono sulla istanza precedente. A regime, quindi, un
task può risiedere su più istanze. Intuitivamente, la componente quot;attivaquot; del
task risiede su di una sola istanza, mentre l'archivio storico può risiedere su più
istanze.
46
47. 3. I dati di un task consistono di una sequenza di data-chunk, ognuno
corrispondente ad un intervallo temporale. Data-chunk corrispondenti a
intervalli consecutivi risiedono, tipicamente, su istanze diverse. Idealmente,
l'unione di tutti i data-chunk (di uno stesso task) dovrebbe formare un
intervallo continuo senza sovrapposizioni. In pratica può accadere che:
ci siano intervalli (sperabilmente brevi) non associati a nessun chunk, in
caso di guasto di un warden non gestito in maniera fault-tolerant;
ci siano intervalli (tipicamente brevi) associati a più chunk. Questi intervalli
corrispondono al tempo necessario per completare una riconfigurazione
per prestazioni: il descrittore quot;vecchioquot; dovrà essere reso inerte solo dopo
che è stato attivato il descrittore quot;nuovoquot;.
4. Ogni data-chunk contiene, oltre ai dati, l'indicazione di:
task a cui appartiene;
status: inProgress/completed (relativo al data-chunk, non al task);
numero d'ordine del data-chunk nel task;
istanza su cui risiede il prossimo chunk (possibly NULL, se è l'ultimo data-
chunk del task)
istanza su cui risiede il precedente chunk (possibly NULL, se è il primo data-
chunk del task)
MIGRAZIONE
La migrazione di un Task da un'istanza A ad un'istanza B deve essere implementata
sul controllore come segue:
1. su A: preleva descrittore
2. su B: crea descrittore
3. su A: termina e collega a B
4. su B: collega ad A
5. sul controllore: aggiorna la tabella dei Task
Se si verifica un errore (guasto) durante l'operazione, all'operatore viene mostrato il
messaggio quot;non so se è stata eseguitaquot;.
Il tutto funziona perché:
guasto tra 1 e 2, l'operazione non è stata eseguita;
guasto tra 2 e 3, il repair thread rileverà, quando analizza l'istanza B, che il
controllore ritiene che il Task risiede su A mentre in realtà risiede su B;
pertanto il repair thread:
47
48. o verifica su A se il task è terminato e collegato a B; se si, esegue 4 e 5;
o else, verifica su A se il task è terminato e collegato a un'istanza diversa
da B; se si, elimina il Task da B;
o else (task su A non terminato), esegue 3, 4 e 5
guasto tra 3 e 4 oppure tra 4 e 5, simile a quanto sopra
A.2.3 ISTANZE
OPERAZIONI ESPORTATE
Ogni operazione viene eseguita in modo sincrono (il chiamante si blocca sino alla
ricezione della risposta).
Da incapsulare in stateless bean
Da raffinare i parametri, in particolare quelli di ritorno e le eventuali eccezioni
createTask(IN task_id, IN altreComponentiDescrittore)
terminateTask(IN task_id)
per migrare un task da A verso B, si esegue getTaskDescr su A, create su B,
terminateAndLink su A, linkFrom su B (vedi le note realizzative dei Task)
terminateTaskAndLinkTo(IN task_id, IN instance_desc)
linkFrom(IN task_id, IN instance_desc)
getTaskDescr(IN task_id, OUT task_descr)
getTaskDataChunk(IN task_id, OUT data_chunk)
getTaskLastReading(IN task_id, OUT reading)
getActiveTasks(OUT setOfTaskIds) (insieme di task quot;attiviquot;, per i quali cioè c'è il
descrittore)
getActiveTasksOnLine(OUT setOfTaskIds) (come il precedente, senza i task
simulati)
getActiveTasksSimulated(OUT setOfTaskIds) (come il precedente, per i soli task
simulati)
getAllTasks(OUT setOfTaskIds) (insieme di tutti i task, anche di quelli per i quali
c'è solo un chunk e non un descrittore).
getActiveWardens(OUT setOfWardenIds) (simile ai Task ma per gli Warden, un
Warden attivo è uno per il quale c'è almeno un Task attivo)
getAllWardens(OUT setOfWardenIds)
getInstanceAlerts(IN date) (data dell'ultimo instance alert ricevuto; torna tutti
quelli successivi a questa data)
48
49. getContentAlerts(IN task_id, IN date) (idem, per il task specificato)
getNetworkAlerts(IN task_id, IN date) (idem, per il task specificato)
NOTE REALIZZATIVE
1. Ogni istanza contiene (almeno) uno scheduling thread ed un insieme di
message bean. I message bean sono tutti identici, ognuno preleva un reading e
lo valuta secondo quanto indicato nel messaggio di attivazione (ogni bean
esegue automaticamente nel contesto di un thread). Lo scheduling thread si
sveglia ad istanti regolari ed invia un messaggio opportuno ai vari bean, in base
ai task in corso.
2. L'indice di carico cpuLoadIndex potrebbe essere legato alla quantità di tempo
tra il completamento dell'ultimo message bean e il prossimo risveglio dello
scheduling thread: più è piccolo questo tempo, maggiore è il load index.
3. Quando un message bean trova nella propria input queue più di un messaggio,
significa che l'istanza è sovraccarica.
(Documento redatto dal relatore prof. A. Bartoli, dal correlatore prof. E. Medvet e dal
dott. G. Davanzo)
49
50. 6 - FONTI
Documentazione ufficiale di Java Standard edition
(http://java.sun.com/javase/6/docs/)
Documentazione ufficiale Java Entrerprise Edition 5
(http://java.sun.com/javaee/reference/index.jsp)
Documentazione ufficiale GlassFish
(https://glassfish.dev.java.net/docs/project.html)
Documentazione ufficiale Shoal (https://shoal.dev.java.net/nonav/docs/api/)
Documentazione ufficiale PostgreSQL (http://www.postgresql.org/docs/)
Zone-H (http://www.zone-h.org)
Tesi di laurea del dott. Giorgio Davanzo: Valutazione di algoritmi di anomaly
detection per la rilevazione automatica delle intrusioni in siti web.
Marco Mauri
50