Checked vs. Unchecked Exception

La gestione delle eccezioni da parte di un linguaggio di programmazione si divide in due grandi famiglie: Checked e Unchecked. Sappiamo inoltre che la corretta gestione degli errori è anche una best practice per la programmazione sicura.

Esempio di linguaggio (forse l'unico) che implementa la gestione di tipo Checked è Java. In Java se un metodo lancia delle eccezioni (di tipo Checked) siamo obbligati a gestirle mediante blocchi try-catch oppure rilanciare l'eccezione al chiamante segnalandola nella signature del metodo con la keyword throws. Nell'esempio qui sotto abbiamo due tipi di eccezioni: IOException è una eccezione di tipo checked che quindi DEVE essere gestita mediante try-catch o throws, mentre NullPointerException è di tipo unchecked perché NON DEVE necessariamente essere gestita:

public void myMethod() {
try {
f1();
}
catch (IOException e) {
// This is a Checked Exception so I must manage it in a catch or with throws System.out.println(e.toString())
}
catch (NullPointerException npe) {
System.out.println(npe.toString())
// This is an Unchecked exception and I want (but I must not) to manage this kind of exception
}
}

dove

public f1() throws IOException,NullPointerException {
do something that raises IOExcpetion and NullPointerException;
}

Esempio invece di linguaggio che implementa solo eccezioni di tipo Unchecked è C#. In questo caso è compito dello sviluppatore capire se e quale eccezione venga lanciata da un metodo e se gestirla direttamente con try-catch, rilanciarla al chiamante o lasciare che qulcuno la gestisca più in alto. Non esiste nessun meccanismo analogo al "throws" nella signature del metodo e sarà quindi cura dello sviluppatore segnalare nei commenti del metodo quali eccezioni questo rilancia e decidere se poi gestirle con una propria logica.

public void MyMethod() {
try {
f1();
}
catch (IOException e) {
Console.Writeline(e.toString());
}
}

dove

/// F1 Comment
/// < cref="IOException">< /exception >
public f1() {
do something();
if (test) throw new IOException(...);
}


In poche parole è come se in C# vi fossero solo eccezioni di tipo RuntimeException di Java che non richiedono la specifica del throws nel metodo che le può lanciare.

E' bene precisare che il concetto di "gestione" dell'eccezione non si esaurisce certo racchiudendo nel blocco catch{} una logica di segnalazione dell'errore. La gestione sintattica da parte del compilatore ci obbliga, nel caso di Checked exception, ad inserire dei costrutti sintattici che ci "ricordino" di inserire una logica per la gestione dell'errore. Ovviamente il compilatore non può controllare che tale logica sia più o meno corretta. L'esempio banale è il blocco catch{} vuoto!

Ma a prescindere se sia più o meno opportuna una gestione del primo tipo o del secondo, questi due approcci hanno inevitabilmente delle ripercussioni anche sulla sicurezza del codice che scriviamo. Vediamo quindi quali sono i pro e i contro (secondo me) dei due approcci dal punto di vista della sicurezza del software:

Checked Exception:
  • Pro (- DoS): lo sviluppatore è obbligato a gestire (in qualche modo) le eccezioni e questo minimizza la probabilità di DoS applicativi dovuti ad errori non controllati (ma non l'azzera, vedasi il caso di mascheramento dell'eccezione);
  • Contro (+ Information Leaking): si possono verificare fenomeni di Information Leaking nel caso di log troppo esplicativi che contengono magari dati applicativi anche sensibili (ex: credenziali utente);
  • Contro (+ Spaghetti Code): il codice è meno leggibile in quanto l'inserimento obbligato di blocchi try-catch rischia di tempestare letteralmente il codice, anche quando questi blocchi non implichino necessariamente una corretta gestione dell'errore;
Unchecked Exception:
  • Pro (- Spaghetti Code): il codice è estremamente più leggibile in quanto i blocchi try-catch sono presenti solo laddove lo sviluppatore ha deciso di inserirli e quindi probabilmente di implementare una corretta gestione dell'errore;
  • Pro (-Information Leaking): l'Information Leaking è meno "catch{} driven" e dipende più dal contesto applicativo, questo implica un maggior controllo dei messaggi di errore poiché relativi alla configurazione dell'ambiente di esecuzione dell'applicazione (ex: web.config in ASP.NET);
  • Contro (+ DoS): probabilità di errori non gestiti, e quindi di DoS, più alta rispetto alle Checked exception poiché è molto facile "scordarsi" di gestire un'eccezione anche banale (IOException).

In conclusione potremmo dire che mentre le Checked Exception diminuiscono la probabilità di DoS, aumentando quella di Information Leaking e Spaghetti Coding, le Unchecked Exception sono speculari rispetto a queste ultime, aumentando la probabilità di DoS e diminuendo quella di Information Leaking e Spaghetti Coding.

Se poi volete approfondire la filosofia che sta dietro al checked e unchecked potete leggere qui e qui.

Commenti

Post popolari in questo blog

Exploit: icsploit o espluà?

TrueCrypt 5.0: nuova release

ING Direct: ancora con il PAD numerico rotante!