MokaByte 58 - Dicembre 2001 
foto dell'autore non disponibile
SecureMail con JavaMail
di
Pietro Passantini
Le nostre caselle di posta elettronica si trovano sempre sotto possibile rischio di attacchi da parte di hacker e società con pochi scrupoli, ecco un semplice modo di difenderci creando un programma java utilizzando le api JavaMail

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/.


MokaByte® è un marchio registrato da MokaByte s.r.l. 
Java®, Jini® e tutti i nomi derivati sono marchi registrati da Sun Microsystems; tutti i diritti riservati 
E' vietata la riproduzione anche parziale 
Per comunicazioni inviare una mail a info@mokabyte.it