Introduzione
Il tema di questo articolo è sicuramente scottante
e riguarda tutti, la sicurezza delle nostre caselle
postali elettroniche continuamente esposte alle aggressioni
da parte di hacker e di società senza scrupoli.
I tipi di attacchi possono essere di vario generere,
si và dall'e-mail con virus allegati al fenomeno
spam (e-mail che ci arrivano senza essere richieste)
fino al temuto mailbomb, cioè una serie di
e-mail inviate alla nostra casella postale con allegati
di grandi dimensioni che mettono ko il nostro client
di posta.
In questo caso l'unico modo di riaccedere alla nostra
casella postale è quello di collegarsi con
telnet e cancellare i messaggi uno per volta (un bel
lavoraccio ve lo assicuro).
Da quì è nata l'esigenza di creare un
programma che potesse svolgere su una casella postale
sia operazioni di controllo sia tutte quelle operazioni
ripetitive per riacquistarne la riusabilità
(d'altronde il computer è nato per questo).
Il problema principale era dover dialogare con i vari
protocolli mail di comunicazione (pop3,imap,etc..)
che di per sè non sono complicati, ma con java
è possibile oltepassare questo scoglio dialogando
a più alto livello con le api di JavaMail.
Metodi
di sicurezza
Nel nostro programma utilizzeremo tre funzioni che
ci dovrebbero garantire e-mail più sicure.
Le prime due funzioni sono di filtraggio messaggi
la terza è una funzione di utilità.
La prima funzione si chiama filterBlackList() ed utilizza
il sistema della BlackList ovvero la lista nera, consiste
nel creare una lista di indirizzi da eliminare dalla
nostra posta elettronica.
I passi da eseguire sono, creare un file di testo
con una lista di indirizzi e-mail che non vogliamo
ricevere poi il nostro programma si dovrà leggere
tutti gli indirizzi dal file e metterli in una struttura
in memoria.
Infine si connetterà al sever di posta e leggerà
i mittenti di ognuno dei messaggi, se il mittente
si troverà nella lista nera il messaggio verrà
cancellato o in realtà marcato come deleted.
Infatti i server di posta non cancellano subbito il
messaggio ma lo pongono in uno stato di cancellabbile,
stato dal quale è possibile tornare indietro
fino a quando non ci disconettiamo dal server, da
quel momento i messaggi sono cancellati definitivamente.
La seconda funzione si chiama filterWhiteList() il
funzionamento è simile al precedente ma decisamente
più drastico, Infatti si tratta di creare una
lista con i soli indirizzi che vogliamo ricevere.
I passi da eseguire sono gli stessi, creare un file
di testo con gli indirizzi mail che vogliamo ricevere
e il programma provvederà a connettersi al
sever, leggere gli indirizzi dal file ed eliminare
i messaggi con mittente diverso da quello presente
nella lista.
Con queste due funzioni dovremmo essere coperti dagli
attacchi di messaggi indesiderati o inviati da persone
sconosciute, ma non siamo coperti dagli attacchi di
un mailbomb.
Per quello infatti ricorreremo alla funzione di utilità
deleteAllMessage(), ovvero cancella tutti i messaggi,
una utility moto comoda per racquistare la riusabilità
della nostra posta elettronica.
Figura 1 - esempio di una black list
Le
calssi delle Api JavaMail
Iniziamo ad entrare più nel dettaglio la prima
cosa da fare è procurarsi le api JavaMail,
facilmente reperibili dal sito ufficiale di Java http://www.java.sun.com.
La versione che utiliziamo è la 1.2 nel file
zip da scaricare troverete oltre ai file jar contenenti
tutte le classi delle api suddivise in package, anche
una fornitissima documentazione e molti file demo.
Ora vediamo in dettaglio le classi che ci servono
per la realizzazione del nostro programma.
Le classi sono molto ben strutturate in ogetti e permettono
un pieno controllo delle e-mail sia in invio che per
ricezione utilizzando i protocolli più conosciuti,
ovviamente noi utilizzeremo le classi per la ricezione
dei messaggi.
La prima classe che utiliziamo è la Session
che rappresenta una sessione mail che collezziona
un insieme di proprietà e di default utilizzate
nelle api JavaMail, una volta aperta una sessione
può essere condivisa anche da altre applicazioni.
Per creare un oggetto Session dobbiamo usare un suo
metodo statico getDefaultInstance che richiede due
parametri un oggetto properties e un oggetto Authenticator,
l'oggeto properties serve a dare alla Session tutte
quelle informazioni sul sistema operativo che utilizziamo,
mentre la classe Authenticator serve a dare le informazioni
necessarie alla connesione come nome dell'host, numero
della porta del server, nome utente e la password.
Informazioni che possiamo settare anche in un secondo
momento in questa fase il parametro lo mettiamo a
null, vediamo come creare un oggetto Session:
//
Crea un oggetto Session
Properties prop = System.getProperties();
Session session = Session.getDefaultInstance(prop,null);
Il
secondo passo è creare un oggetto Store che
contienne tutte le informazioni sul protocollo da
settare.
Per creare un oggetto Store utilizziamo un metodo
della classe Session getStore che ha come parametro
una stringa che rappresenta il protocollo da usare
es:
//
Crea un oggetto Store
Store store = session.getStore("pop3");
Dall'oggetto
Store è possibile connettersi con il metodo
connect che ha come parametri quelli che occorrono
per la connessione es:
//
Connessione al server
session.connect("mail.dominio.it",110,"utente","password");
A
questo punto possiamo accedere alle cartelle della
nostra posta elettronica tramite l'oggetto Folder
che rappresenta una cartella specifica dove sono memorizzati
i messaggi.
Per creare un oggetto Folder bisogna usare il metodo
getFolder della classe Store che ha come parametro
una stringa che rappresenta il nome della cartella,
nel nostro caso useremo il nome INBOX che si riferisce
alla cartella principale dove il server riceve i messaggi
es:
//
Crea un oggetto Folder
Folder inbox = store.getFolder("INBOX");
Una
volta ottenuto l'oggetto Folder bisogna aprirlo e
settare i diritti sulla cartella.
Diritti che dipendono esclusivamete dall'utente che
si è connesso, il metodo da utilizzare è
open e come parametro utilizziamo delle costanti che
ci vengono messe a disposizione dalle api e si trovano
nell'oggetto Folder, READ_WRITE per date i diritti
di lettura e scrittura READ_ONLY per dare i diritti
di sola lettura.
Nel caso settando i diritti di lettura e scrittura
l'utente loggato non ne abbia facoltà il metodo
produce un eccezione MessagingException, che può
essere catturata per assegnare i soli diritti di lettura
alla cartella es:
//
Apri un Folder
try
{
inbox.open(Folder.READ_WRITE);
}
catch(MessagingException e)
{
inbox.open(Folder.READ_ONLY);
}
Ora
tutto è pronto per accedere ai messaggi.
Per sapere quanti messaggi abbiamo ricevuto possiamo
utilizzare un metoto della classe Folder getMessageCount(),
che ritorna un intero con il numero dei messaggi ricevuti.
Per accedere ad un messaggio utiliziamo il metodi
getMessage che ha come parametro l'indice del messaggio
e restituisce una classe Message es:
//
Leggi il messaggio con l'id 1
Message m = inbox.getMessage(1);
Con
l'oggetto Message è possibile avere tutte le
informazioni del messaggio come l'oggetto, il testo
e il mittente informazione che ci occorre per il nostro
programma.
Il metodo della classe Message da utilizzare è
getFrom() che restituisce un array di Address, che
rappresenta un indirizzo e-mail.
Per ottenere una stringa dalla classe Address dobbiamo
utilizzare il metodo toString() es:
//
Ottenere il mittente dal messaggio
Address[] address = m.getFrom();
String mittente = address[0].toString();
Adesso
siamo a conoscenza di tutte le classi che ci servono
per sviluppare il nostro programma, ci manca solo
sapere come cancellare i messaggi dal server.
Per effettuare questa operazione dobbiamo usare un
metodo della classe Message setFlag che ha due parametri,
il primo è il flag che vogliamo settare per
questo specifico messaggio.
I vari flag si ottengono dalla classe Flags.Flag,
l'oggetto ha varie costanti che permetto di settare
se un messaggio è stato letto, se c'è
un risposta e marcarlo per la cancellazione in quest'ultimo
caso la costante è DELETED, il secondo parametro
è un booleano è serve per dire al metodo
se il flag è attivo oppure no es:
//
Cancellare un messaggio
m.setFlag(Flags.Flag.DELETE);
Per
rendere effettive le modifiche dobbiamo chiudere il
Folder con il metodo close che ha come parametro un
boolean, settato a true elimina i messaggi, a false
ignora il flag sui vari Message es:
//
Chiusura per rendere effettive le modifiche
inbox.close(true);
store.close();
Realizzazione
di SecureMail
Passiamo adesso alla realizzazione del nostro programma,
come descritto in precedenza le funzioni da realizzare
sono tre.
Iniziamo con inportare i package che ci interessano:
//
import dei package
import java.util.*;
import java.io.*;
import javax.mail.*;
import javax.mail.internet.*;
adesso
descriviamo la prima funzione filterBlackList() :
//
funzione filter blacklist
public void filterBlackList(String host,int port,String
user,String password,String protocol)
{
Vector blacklist = new Vector();
try
{
boolean eof = false;
// apertura della file di black list
FileInputStream fis = new FileInputStream("blacklist.txt");
int c=0;
StringBuffer sb = new StringBuffer();
// caricamento della lista in memoria
while(!eof)
{
c = fis.read();
if(c=='\n')
{
blacklist.addElement(sb.toString());
sb = new StringBuffer();
}
else if(c==-1)
{
eof = true;
}
else
sb.append((char)c);
}
}
catch(Exception e)
{
System.out.println(e);
}
..
..
In
questo primo blocco la funzione carica il file con
gli indirizzi e li mette in un oggetto Vector.
//
Proprietà di sistema
Properties prop = System.getProperties();
Session session = Session.getDefaultInstance(prop,null);
try
{
Store store = session.getStore(protocol);
store.connect(host,port,user,password);
System.out.println("Utente Connesso");
Folder inbox = store.getFolder("INBOX");
try
{
inbox.open(Folder.READ_WRITE);
}
catch (MessagingException ex)
{
System.out.println("Aperto in modo solo lettura");
inbox.open(Folder.READ_ONLY);
}
int a = inbox.getMessageCount();
System.out.println("Messaggi Totali:"+a);
..
..
In
questo secondo blocco vediamo come viene aperta la
connessione con il server e come riceviamo il numero
di messaggi ricevuti.
//
controlla se esistono messaggi
if(a<=0)
return;
// scorre tutti i messaggi
for(int mid=0;mid<a;mid++)
{
// lettura di un mesaggio
Message m = inbox.getMessage(mid+1);
// restituisce il mittente del messaggio
Address[] add = m.getFrom();
for(int
i=0;i<add.length;i++)
{
for(int j=0;j<blacklist.size();j++)
{
// Confronta i destinatari dei messaggi con gli
//
indirizzi della black list
if(add[i].toString().indexOf(
((String)blacklist.elementAt(j)).trim())!=-1){
System.out.println("Una e-mail Cancellata");
m.setFlag(Flags.Flag.DELETED, true);
}
}
}
}
System.out.println("Fine");
inbox.close(true);
store.close();
}
catch(Exception e)
{
System.out.println(e);
}
}
Nell'utimo blocco del codice vediamo il ciclo di scorrimento
di tutti i messaggi, lettura del mittente della e-mail
e controllo se esso esiste nel Vector blacklist, nel
caso di esistenza il messaggio viene marcato per la
cancellazione.
La seconda funzione filterWhiteList è totalmente
simile a questa cambia solo per il tipo di filtraggio,
infatti basterà cambiare il controllo sui mittenti:
..
..
// Confronta i mittenti dei messaggi con gli indirizzi
della white list
if(add[i].toString().indexOf(
((String)whaitlist.elementAt(j)).trim())==-1)
{
System.out.println("Una e-mail Cancellata");
m.setFlag(Flags.Flag.DELETED, true);
}
..
..
Infine
la terza funzione sarebbe fatta, visto che si tratta
di cancellare tutte le e-mail basterebbe cancellare
il filtro e marcare direttamente tutti i messaggi
DELETED.
Ma in questo modo corriamo il rischio di dover leggere
tutte le e-mail prima di poterle cancellare, infatti
la funzione getMessage provoca lo scaricamento del
messaggio con grande perdita di tempo.
Nel caso di un mailbomb ci comporteremmo alla stessa
maniera di un client di posta, per evitare questo
possiamo settare il flag sui messaggi a livello di
Folder con il suo metodo setFlags la sintassi completa
è:
//
dichiarazione del metodo setFlags della classe Folder
public void setFlags(int start, int end,Flags flag,
boolean value) throws MessagingExceprion
Dove
con start e end indichiamo l'intervallo dei messagi
da settare con un determinato flag e value rappresenta
l'attivazione del flag.
Quindi nel nostro caso nella funzione deleteAllMessage()
dopo aver aperto la connessione al server e aver letto
il numero di messaggi arrivati possiamo usare queseo
singolo metoto
..
..
// marca tutti i messaggi ricevuti per la cancellazione
inbox.setFlags(1,a,new Flags(Flags.Flag.DELETED),true);
..
..
Conclusioni
In conclusione possiamo dire che le api JvavaMail
sono un ottimo strumento per programmare applicazioni
rivolte alla posta elettronica e il tema della sicurezza
sulle e-mail meriterebbe senza dubbio più cosiderazione
soprattutto da perte delle grandi Software hause.
Un otima soluzione potrebbe essere di integrare tutte
queste metodologie di sicurenza in un client di posta,
magri creato con le api JavaMail che permettono una
gestione completa di vari protocolli mail.
Bibliografia
[1] Sun microsistems - "JavaMail Guide for Service
Providers", Sun microsistems, 1998
[2] Sun microsistems - "JavaMail Designe Specification",
Sun microsistems, 2000
Pietro Passantini nato Napoli
svolge da anni l'attività di programmatore
e progettista in tecnologie object oriented si diverte
gestendo un sito su Java http://digilander.iol.it/tuttojava/.
|