Sei sulla pagina 1di 31

Tradotto dal Inglese al Italiano - www.onlinedoctranslator.

com

13
Condizioni di gara

205
206 24 peccati capitali della sicurezza del software

PANORAMICA DEL PECCATO


La definizione di una condizione di competizione è quando due diversi contesti di esecuzione, siano essi
thread o processi, sono in grado di modificare una risorsa e interferire l'uno con l'altro. Il difetto tipico è
pensare che una breve sequenza di istruzioni o chiamate di sistema verrà eseguita in modo atomico e
che non è possibile che un altro thread o processo possa interferire. Anche quando vengono
presentate prove evidenti dell'esistenza di un tale bug, molti sviluppatori ne sottovalutano la gravità. In
realtà, la maggior parte delle chiamate di sistema finisce per eseguire molte migliaia (a volte milioni) di
istruzioni e spesso non vengono completate prima che un altro processo o thread ottenga un intervallo
di tempo.
Anche se non possiamo entrare nei dettagli qui, una semplice race condition in un ping sweeper
multithread una volta disabilitava completamente un provider di servizi Internet per la maggior parte della
giornata. Una risorsa comune protetta in modo improprio ha fatto sì che l'app eseguisse ripetutamente il ping
di un singolo indirizzo IP a una velocità molto elevata. Le condizioni di competizione si verificano in modo più
affidabile sui sistemi multiprocessore e, data la realtà dei processori attuali, i sistemi che hanno o si
comporteranno come se fossero presenti due processori sono la norma: i sistemi a processore singolo sono
relegati all'estremità più bassa della scala di calcolo. Ora esistono sistemi desktop convenienti con un
massimo di otto contesti di esecuzione simultanea, con quattro core di processore effettivi.
È realistico aspettarsi che i problemi con le condizioni di gara diventino significativamente più
frequenti, soprattutto perché pochi programmatori sono esperti nella programmazione
simultanea.

RIFERIMENTI CWE
Il riferimento CWE a questo problema è molto diretto, ma ci sono diversi nodi figli che
illustrano l'entità del problema e il numero di modi in cui può emergere.

- CWE-362: Race Condition (genitore)


- CWE-364: condizione di gara del gestore del segnale

- CWE-365: Race Condition in Switch


- CWE-366: Race Condition all'interno di un thread

- CWE-367: Condizione di competizione TOCTOU (Time-of-Check Time-of-Use).

- CWE-368: condizione di competizione per il cambio di contesto

- CWE-370: Race Condition nel controllo della revoca del certificato


- CWE-421: Race Condition durante l'accesso al canale alternativo

Alcuni di questi problemi non sono comuni e non sono trattati in questo capitolo, ad esempio, le revoche
di certificati tendono ad essere rare nella maggior parte degli scenari di utilizzo e, se non è nel tuo scenario,
c'è una soluzione chiara, che consiste nell'insistere nel controllare il CRL (lista di revoca dei certificati), oltre a
fissare un limite di tempo ridotto per quanto tempo un elenco potrebbe essere valido.
Peccato 13: Race Condition 207

LINGUE INTERESSATE
Come per molti problemi, è possibile creare race condition in qualsiasi lingua. Un
linguaggio di alto livello che non supporta thread o processi biforcuti non sarà vulnerabile
ad alcuni tipi di race condition, ma le prestazioni relativamente lente di questi linguaggi di
alto livello li rendono più suscettibili agli attacchi in base al tempo di verifica. d'uso
(TOCTOU).

IL PECCATO SPIEGATO
L'errore di programmazione principale che porta a condizioni di gara è fare qualcosa che
qualsiasi buon testo di programmazione ti dirà di non fare, ovvero programmare con effetti
collaterali. Se una funzione non è rientrante e due thread sono contemporaneamente nella
funzione, allora le cose si romperanno. Come probabilmente avrai già capito, quasi ogni tipo di
errore di programmazione, data la sfortuna da parte tua e lo sforzo da parte dell'attaccante, può
essere trasformato in un exploit. Ecco un'illustrazione C++:

lista<unsigned long> g_TheList;

unsigned long GetNextFromList() {

long ret senza segno = 0; if(!


g_TheList.empty())
{
ret = g_TheList.front();
g_TheList.pop_front();
}
ritorno ret;
}

Potresti pensare che le tue probabilità che due thread siano contemporaneamente nella funzione
siano basse, ma sotto questa piccolissima quantità di codice C++ si nascondono molte istruzioni. Tutto
ciò che serve è che un thread superi il controllo se l'elenco è vuoto appena prima che un altro chiami
pop_front() sull'ultimo elemento. Come diceva Clint Eastwood nel filmSporco Harry: “Mi sento
fortunato?” Un codice molto simile a questo ha impedito a un ISP di servire i propri clienti per la
maggior parte di un giorno.
Un'altra incarnazione del problema sono le condizioni di corsa del segnale. Questo attacco è
stato descritto pubblicamente per la prima volta in "Delivering Signals for Fun and Profit:
Understanding, Exploiting, and Preventing Signal-Handling Related Vulnerabilities" di Michal
Zalewski, disponibile all'indirizzo http://lcamtuf.coredump.cx/signals.txt. Il problema qui è che
molte applicazioni UNIX non si aspettano di incontrare i tipi di problemi che vedresti nelle app
multithread.
208 24 peccati capitali della sicurezza del software

Dopotutto, anche le applicazioni simultanee in esecuzione su sistemi UNIX e simili a UNIX


normalmente eseguirebbero il fork di una nuova istanza, quindi quando qualsiasi variabile globale
viene modificata, quel processo ottiene la propria copia della pagina di memoria a causa della
semantica di copia su scrittura. Molte applicazioni implementano quindi gestori di segnale e talvolta
mappano persino lo stesso gestore su più di un segnale. La tua app è semplicemente seduta lì a fare
tutto ciò che dovrebbe fare quando l'attaccante le invia una coppia di segnali a fuoco rapido e, prima
che tu te ne accorga, la tua app è diventata essenzialmente multithread! È abbastanza difficile scrivere
codice multithread quando ti aspetti problemi di concorrenza, ma quando non lo sei, è quasi
impossibile.
Una classe di problemi deriva dalle interazioni con file e altri oggetti. Hai modi
quasi illimitati per metterti nei guai con questi. Ecco alcuni esempi. La tua app deve
creare un file temporaneo, quindi controlla prima se il file esiste già e, in caso
contrario, crea il file. Sembra una cosa comune da fare, vero? Lo è, ma ecco l'attacco:
l'attaccante capisce come assegni un nome ai file e inizia a creare collegamenti a
qualcosa di importante dopo aver visto l'avvio della tua app.
La tua app è sfortunata, apre un collegamento che in realtà è il file scelto dall'attaccante e quindi
una delle diverse azioni può causare un'escalation di privilegi. Se elimini il file, l'attaccante potrebbe ora
essere in grado di sostituirlo con uno che realizza scopi malvagi. Se si sovrascrive il file esistente,
potrebbe verificarsi un arresto anomalo di qualcosa o un errore imprevisto. Se si suppone che il file
venga utilizzato da processi non privilegiati, è possibile modificare le autorizzazioni su di esso,
concedendo all'attaccante il permesso di scrittura per qualcosa di sensibile. La cosa peggiore che può
accadere è che la tua app imposti il file suid root, e ora l'applicazione scelta dall'attaccante può essere
eseguita come root.
Quindi sviluppi per i sistemi Windows e sei seduto lì a pensare compiaciuto che niente di tutto questo si
applica a te, ripensaci. Eccone uno che ha colpito Windows: quando un servizio si avvia, finisce per creare una
named pipe che il gestore del controllo del servizio utilizza per inviare i messaggi di controllo del servizio. Il
gestore del controllo del servizio viene eseguito come sistema, ovvero l'account con privilegi maggiori sul
sistema. L'attaccante dovrebbe capire quale pipe creare, trovare un servizio che può essere avviato da utenti
ordinari (molti di questi esistono per impostazione predefinita), quindi impersonare il gestore del controllo del
servizio una volta che si connette alla pipe.
Questo problema è stato risolto in due fasi: in primo luogo, il nome della pipe è stato reso
imprevedibile, riducendo notevolmente la finestra di opportunità per l'attaccante, quindi in
Windows Server 2003 impersonare altri utenti è diventato un privilegio. Potresti anche pensare
che Windows non supporti i collegamenti, ma lo fa; vedere la documentazione per
CreateHardLink e Windows Vista e versioni successive supportano i veri soft link. Non hai bisogno
di molto accesso al file a cui sei collegato. Windows ha un gran numero di oggetti con nomi
diversi (file, pipe, mutex, sezioni di memoria condivisa, desktop e altri) e ognuno di questi può
causare problemi se il tuo programma non si aspetta che esistano all'inizio.

Codice peccaminoso

Anche se sceglieremo C, questo codice potrebbe essere scritto in qualsiasi lingua e c'è ben poco
che sia specifico della lingua al riguardo. Questo è un errore che è una combinazione
Peccato 13: Race Condition 209

di errore di progettazione e incapacità di comprendere e aggirare le sfumature del sistema operativo.


Non siamo a conoscenza di alcuna lingua che renda le condizioni di gara significativamente più difficili
da creare. Ecco alcuni frammenti di codice e cosa può andare storto:

carattere*tmp;
FILE* pTempFile;

tmp = _tempnam("/tmp", "MyApp");


pTempFile = fopen(tmp, "w+");

Sembra abbastanza innocuo, ma l'attaccante può, in generale, indovinare quale sarà il prossimo
nome file. In un'esecuzione di test sul sistema dell'autore, chiamate ripetute hanno generato file
denominati MyApp1, MyApp2, MyApp3 e così via. Se i file vengono creati in un'area in cui l'aggressore
può scrivere, l'aggressore potrebbe essere in grado di creare in anticipo il file temporaneo,
eventualmente sostituendolo con un collegamento. Se l'applicazione sta creando diversi file
temporanei, l'attacco diventa molto più semplice.

Peccati correlati
Ci sono diversi problemi correlati trattati qui. Il peccato principale è l'incapacità di scrivere codice che
gestisca correttamente la concorrenza. I peccati correlati non utilizzano controlli di accesso adeguati,
trattati in Sin 12, e il mancato utilizzo di numeri casuali generati correttamente, trattati in Sin 18. Quasi
tutte le race condition dei file temporanei sono solo problemi perché sono stati utilizzati controlli di
accesso impropri, che è tipicamente aggravato da versioni precedenti del sistema operativo che non
forniscono directory temporanee adeguatamente protette per utente. La maggior parte dei sistemi
operativi attuali fornisce spazio scratch per utente e, anche se non viene fornito, è sempre possibile per
lo sviluppatore dell'applicazione creare spazio scratch sotto la home directory di un utente.

La mancata generazione corretta di numeri casuali entra in gioco quando è necessario creare
un file, una directory o un altro oggetto univoco in un'area pubblica. Se usi un generatore di
numeri pseudo-casuali o, peggio ancora, incrementi prevedibilmente il nome, allora l'attaccante
può spesso indovinare cosa creerai dopo, che spesso è il primo passo sulla tua strada verso la
rovina.
Si noti che molte delle funzioni per i nomi di file temporanei fornite dal sistema sono
garantite per creare nomi di file univoci, non nomi di file imprevedibili. Se stai creando file o
directory temporanei in un luogo pubblico, potresti voler utilizzare le funzioni di
generazione di numeri casuali appropriate per creare i nomi. Un approccio è documentato
nel capitolo 23 di Scrittura di codice sicuro, seconda edizionedi Michael Howard e David C.
LeBlanc (Microsoft Press, 2002), e anche se il codice di esempio è per Windows, l'approccio è
molto portabile.
210 24 peccati capitali della sicurezza del software

INDIVIDUARE IL MODELLO DEL PECCATO


Le race condition si trovano comunemente nelle seguenti condizioni:

- Più di un thread o processo deve scrivere sulla stessa risorsa. La risorsa potrebbe essere la
memoria condivisa, il file system (ad esempio, da più applicazioni Web che manipolano i dati
in una directory condivisa), altri archivi di dati come il registro di Windows o persino un
database. Potrebbe anche essere una variabile condivisa!

- Creazione di file o directory in aree comuni, come directory per file temporanei
(come /tmp e /usr/tmp in sistemi simili a UNIX).
- Gestori di segnali.

- Funzioni non rientranti in un'applicazione multithread o un gestore di segnali. Si


noti che i segnali sono quasi inutili sui sistemi Windows e non sono suscettibili a
questo problema.

INDIVIDUARE IL PECCATO DURANTE LA REVISIONE DEL CODICE


Per individuare le aree in cui la concorrenza può causare problemi, devi prima esaminare il tuo codice e
le funzioni di libreria che chiami. Il codice non rientrante manipolerà le variabili dichiarate al di fuori
dell'ambito locale, come variabili globali o statiche. Se una funzione usa una variabile interna statica,
anche questo renderà la funzione non rientrante. Sebbene l'utilizzo di variabili globali sia generalmente
una cattiva pratica di programmazione che porta a problemi di manutenzione del codice, le variabili
globali da sole non si sommano a una race condition.
L'ingrediente successivo è che devi essere in grado di modificare le informazioni in modo
incontrollato. Ad esempio, se dichiari un membro statico di una classe C++, quel membro viene
condiviso tra tutte le istanze della classe e diventa essenzialmente globale. Se il membro viene
inizializzato al caricamento della classe e viene letto solo in seguito, non hai problemi. Se la
variabile viene aggiornata, è necessario inserire dei blocchi in modo che nessun altro contesto di
esecuzione sia in grado di modificarla. La cosa importante da ricordare nel caso speciale di un
gestore di segnale è che il codice deve essere rientrante, anche se il resto dell'applicazione non si
preoccupa dei problemi di concorrenza. Osserva attentamente i gestori di segnali, inclusi tutti i
dati che manipolano, in particolare le variabili globali.
Il prossimo caso di race condition di cui preoccuparsi è il caso di processi esterni al tuo
che interferiscono con il tuo processo. Le aree da cercare sono la creazione di file e
directory in aree scrivibili pubblicamente e l'uso di nomi di file prevedibili.
Osserva attentamente ogni caso in cui i file (come i file temporanei) vengono creati in una
directory condivisa (come /tmp o /usr/tmp nei sistemi simili a UNIX o \Windows\temp nei sistemi
Microsoft). I file dovrebbero sempre essere creati in directory condivise usando l'equivalente
dell'opzione O_EXCL della chiamata C open(), o CREATE_NEW quando si chiama CreateFile, che
riesce solo se viene creato un nuovo file. Avvolgi questa richiesta in un ciclo che continua
Peccato 13: Race Condition 211

crea nuovi nomi di file utilizzando input veramente casuali e riprova a creare il file. Se usi caratteri
correttamente randomizzati (facendo attenzione a mappare solo caratteri legali per il tuo file system),
le possibilità di doverlo chiamare due volte saranno basse. Sfortunatamente, la chiamata fopen() di C
non ha un modo standard per richiedere O_EXCL, quindi è necessario utilizzare open() e quindi
convertire il valore restituito in un valore FILE*.
Su un sistema Microsoft, non solo le chiamate API Windows native come CreateFile sono più
flessibili, ma tendono anche a funzionare meglio. Inoltre, è possibile stabilire controlli di accesso
al file (o altro oggetto) in modo atomico al momento della creazione, il che elimina ancora più
possibilità di malizia.
Non dipendere mai solo da routine come mktemp(3) per creare un "nuovo" nome file; dopo
l'esecuzione di mktemp(3), un utente malintenzionato potrebbe aver già creato un file con lo stesso
nome. La shell UNIX non ha un'operazione integrata per farlo, quindi qualsiasi operazione comels > /
tmp/list.$$è una condizione di gara in attesa di accadere; gli utenti di shell dovrebbero invece usare
mktemp(1). Alcuni degli strumenti di analisi del codice stanno iniziando a essere in grado di trovare
potenziali race condition e deadlock nel codice C/C++ durante l'analisi statica.

TECNICHE DI PROVA PER TROVARE IL PECCATO


Le condizioni di gara possono essere difficili da trovare attraverso i test, ma ci sono alcune tecniche per
trovare il peccato. Una delle tecniche più semplici consiste nell'eseguire i passaggi di prova su un
sistema multiprocessore veloce. Se inizi a vedere arresti anomali che non puoi riprodurre su un sistema
a processore singolo, quasi sicuramente hai scoperto una race condition.
Per trovare problemi di gestione del segnale, creare un'applicazione per inviare i segnali in modo
ravvicinato all'applicazione sospetta e vedere se è possibile che si verifichino arresti anomali. Tieni presente
che un singolo test per una condizione di competizione non sarà sufficiente: il problema potrebbe presentarsi
solo di rado.
Per trovare corse di file temporanei, abilitare la registrazione sul file system o strumentare l'applicazione
per registrare le chiamate di sistema. Osserva attentamente qualsiasi attività di creazione di file e chiedi se i
file con nomi prevedibili vengono creati nelle directory pubbliche. Se puoi, abilita la registrazione che ti
consentirà di determinare che l'opzione O_EXCL viene utilizzata correttamente quando i file vengono creati
nelle directory condivise. Le aree di particolare interesse sono quando un file viene originariamente creato
con autorizzazioni improprie e quando viene successivamente rafforzato. La finestra di opportunità tra le due
chiamate può consentire a un utente malintenzionato di sfruttare il programma. Allo stesso modo, qualsiasi
riduzione dei privilegi necessari per accedere al file è sospetta. Se l'attaccante può far sì che il programma
operi su un collegamento invece che sul file previsto, qualcosa che avrebbe dovuto essere limitato potrebbe
diventare accessibile.

ESEMPIO PECCATI
Le seguenti voci in Common Vulnerabilities and Exposures (CVE) su http://
cve.mitre.org/ sono esempi di race condition.
212 24 peccati capitali della sicurezza del software

CVE-2008-0379
Dalla descrizione CVE:

La race condition nel controllo Enterprise Tree ActiveX (EnterpriseControls.dll 11.5.0.313) in Crystal
Reports XI Release 2 consente agli aggressori remoti di causare un Denial of Service (arresto
anomalo) ed eventualmente eseguire codice arbitrario tramite il metodo SelectedSession, che
attiva un overflow del buffer.

CVE-2008-2958
Dalla descrizione IBM/ISS:

CheckInstall potrebbe consentire a un utente malintenzionato locale di lanciare un attacco di collegamento


simbolico, causato da un errore negli script checkinstall e installwatch. Alcune directory vengono create con
autorizzazioni non sicure. Un utente malintenzionato locale potrebbe sfruttare questa vulnerabilità creando
un collegamento simbolico da un file temporaneo ad altri file nel sistema, che consentirebbe all'utente
malintenzionato di sovrascrivere file arbitrari nel sistema con privilegi elevati.

CVE-2001-1349
Dalla descrizione CVE:

Sendmail prima della 8.11.4 e 8.12.0 prima della 8.12.0.Beta10, consente agli utenti locali di causare un
denial of service e possibilmente corrompere l'heap e ottenere privilegi tramite race condition nei
gestori di segnali.

Questa è la condizione di corsa del segnale documentata nell'articolo di Zalewski sulla consegna dei
segnali, a cui abbiamo fatto riferimento in precedenza. La condizione sfruttabile si verifica a causa di un
double-free su una variabile globale che viene colpita al rientro nella routine di gestione del segnale. Sebbene
né l'avviso di Sendmail, né il database delle vulnerabilità di SecurityFocus facciano riferimento a codice exploit
disponibile pubblicamente, è interessante notare che esiste un collegamento (morto) al codice exploit nel
documento originale.

CAN-2003-1073
Dalla descrizione CVE:

Una race condition nel comando at per Solaris da 2.6 a 9 consente agli utenti locali di eliminare file
arbitrari tramite l'argomento -r con sequenze .. (punto punto) nel nome del processo, modificando quindi
la struttura della directory dopo aver verificato le autorizzazioni per eliminare il file e prima che la
cancellazione avvenga effettivamente.
Peccato 13: Race Condition 213

Questo impresa È dettagliato A www.securityfocus.com/archive/1/308577/


2003-01-27/2003-02-02/0, e combina una condizione di competizione con un errore nel controllare
correttamente che i nomi dei file non contengano ../, il che farebbe sì che lo scheduler at rimuova i file
al di fuori della directory immagazzinato.

CVE-2000-0849
Dalla descrizione CVE:

La condizione di competizione nel server Microsoft Windows Media consente agli aggressori remoti
di causare un Denial of Service nel servizio Unicast di Windows Media tramite una richiesta errata,
nota anche come vulnerabilità "Unicast Service Race Condition".

Ulteriori dettagli su questa vulnerabilità sono disponibili all'indirizzo www.microsoft.com/technet/


security/Bulletin/MS00-064.mspx. Una richiesta "malformata" pone il server in uno stato in cui le
richieste successive provocano un errore del servizio fino al riavvio del servizio.

FASI DI RISCATTO
Uno dei primi passi verso la redenzione è capire come scrivere correttamente il codice rientrante.
Anche se non pensi che l'applicazione verrà eseguita in un ambiente con thread, se le persone provano
a eseguire il porting dell'applicazione o a superare i blocchi dell'applicazione utilizzando più thread, lo
apprezzeranno quando non programmi con effetti collaterali. Una considerazione sulla portabilità è
che Windows non implementa correttamente fork(), la creazione di nuovi processi in Windows è molto
costosa e la creazione di nuovi thread è molto economica.
Mentre la scelta di utilizzare processi o thread varia a seconda del sistema
operativo scelto e dell'applicazione, il codice che non dipende dagli effetti collaterali
sarà più portabile e molto meno soggetto a race condition.
Se si sta tentando di gestire contesti di esecuzione simultanea, tramite processi o thread
biforcuti, è necessario proteggersi attentamente sia dalla mancanza di blocco delle risorse
condivise sia dal blocco errato delle risorse. Questo argomento è stato trattato in modo molto
più dettagliato altrove, quindi lo tratteremo solo brevemente qui. Cose da considerare:

- Se il tuo codice genera un'eccezione non gestita mentre mantieni un blocco, bloccherai qualsiasi
altro codice che richiede il blocco. Un modo per uscirne è trasformare l'acquisizione e il rilascio
del blocco in un oggetto C++ in modo che quando lo stack si svolge, il distruttore rilascerà il
blocco. Tieni presente che potresti lasciare la risorsa bloccata in uno stato instabile; in alcuni casi,
potrebbe essere preferibile eseguire un deadlock piuttosto che continuare in uno stato indefinito.

- Acquisisci sempre più blocchi nello stesso ordine e rilasciali nell'ordine opposto
rispetto a come sono stati acquisiti. Se pensi di aver bisogno di più serrature per fare
qualcosa, pensaci ancora un po'. Un design più elegante può risolvere il problema
con minore complessità.
214 24 peccati capitali della sicurezza del software

- Fai il meno possibile mentre tieni un lucchetto. Per contraddire il consiglio del punto
elenco precedente, a volte più blocchi possono consentire di utilizzare un buon livello di
granularità e ridurre effettivamente la possibilità di un deadlock e migliorare
sostanzialmente le prestazioni dell'applicazione. Questa è un'arte, non una scienza.
Progetta attentamente e fatti consigliare da altri sviluppatori.

- Non dipendere mai da una chiamata di sistema per completare l'esecuzione prima che un'altra
applicazione o thread possa essere eseguita. Le chiamate di sistema possono variare da migliaia a
milioni di istruzioni. Dal momento che è sbagliato aspettarsi che una chiamata di sistema venga
completata, non iniziare nemmeno a pensare che due chiamate di sistema vengano completate
insieme.

Se stai eseguendo un gestore di segnali o un gestore di eccezioni, l'unica cosa veramente sicura da fare
potrebbe essere chiamare exit(). Il miglior consiglio che abbiamo visto sull'argomento è tratto dall'articolo di
Michal Zalewski, "Fornire segnali per divertimento e profitto: comprensione, sfruttamento e prevenzione delle
vulnerabilità correlate alla gestione dei segnali":

- Usa solo chiamate lib rientranti sicure nei gestori di segnali. Ciò richiede importanti
riscritture di numerosi programmi. Un'altra mezza soluzione consiste nell'implementare
un wrapper attorno a ogni libcall insicuro utilizzato, controllando uno speciale flag globale
per evitare il rientro.

- Blocca l'invio del segnale durante tutte le operazioni non atomiche e/o costruisci gestori di
segnale in un modo che non farebbe affidamento sullo stato interno del programma (ad
esempio, impostazione incondizionata di un flag specifico e nient'altro).

- Blocca la consegna del segnale nei gestori di segnale.

Per affrontare i problemi di TOCTOU, una delle migliori difese è creare file in luoghi in cui gli
utenti ordinari non hanno accesso in scrittura. Nel caso delle directory, potresti non avere
sempre questa opzione. Quando si programma per piattaforme Windows, ricordare che un
descrittore di sicurezza può essere allegato a un file (o qualsiasi altro oggetto) al momento della
creazione. Fornire i controlli di accesso al momento della creazione elimina le race condition tra
la creazione e l'applicazione dei controlli di accesso. Per evitare race condition tra il controllo
dell'esistenza di un oggetto e la creazione di uno nuovo, sono disponibili un paio di opzioni, a
seconda del tipo di oggetto.
L'opzione migliore, che può essere utilizzata con i file, consiste nello specificare il flag CREATE_NEW
nell'API CreateFile. Se il file esiste, la chiamata avrà esito negativo. La creazione di directory è più semplice:
tutte le chiamate a CreateDirectory falliranno se la directory esiste già. Anche così, c'è un'opportunità per i
problemi. Diciamo che hai inserito la tua app in C:\Program Files\MyApp, ma un utente malintenzionato ha già
creato la directory. L'attaccante avrà ora il controllo completo dell'accesso alla directory, che include il diritto
di eliminare i file all'interno della directory, anche se il file stesso non concede l'accesso all'eliminazione a
quell'utente. Diversi altri tipi di oggetto non consentono il passaggio di un parametro per determinare la
semantica create new rispetto a open always e queste API avranno esito positivo, ma restituiranno
ERROR_ALREADY_EXISTS a GetLastError. Il corretto
Peccato 13: Race Condition 215

modo per affrontare questo problema se vuoi assicurarti di non aprire un oggetto esistente è scrivere
codice come questo:

MANIGLIA hMutex = CreateMutex(...args...);

if(hMutex == NULL)
restituire falso;

if(GetUltimoErrore() == ERRORE_GIA_ESISTENTE) {

CloseHandle(hMutex);
restituire falso;
}

MISURE EXTRA DIFENSIVE


Cerca di evitare completamente questo problema creando file temporanei in un archivio per
utente, non in un archivio pubblico. Scrivi sempre codice rientrante, anche se non ti aspetti che
l'app sia multithread. Qualcuno potrebbe volerlo trasferire e scoprirai anche che il codice è più
manutenibile e robusto.

ALTRE RISORSE
- “La contesa delle risorse può essere usata contro di te" di David Wheeler:
www-106.ibm.com/developerworks/linux/library/
l-sprace.html?ca=dgr-lnxw07RACE
- Argomenti di ricerca RAZOR: http://razor.bindview.com/
publish/papers/signals.txt
- “Fornire segnali per divertimento e profitto: comprensione, sfruttamento e
prevenzione delle vulnerabilità correlate alla gestione dei segnali” di Michal
Zalewski: www.bindview.com/Services/Razor/Papers/2001/signals.cfm.

RIEPILOGO
- Farescrivere un codice che non dipenda dagli effetti collaterali.

- Farefare molta attenzione quando si scrivono gestori di segnali.

- Nonmodificare le risorse globali senza bloccare.


- Prendere in considerazionescrivere file temporanei in un archivio per utente invece che in uno spazio

scrivibile a livello mondiale.


Questa pagina è stata lasciata vuota intenzionalmente
14
Scarsa usabilità

217
218 24 peccati capitali della sicurezza del software

PANORAMICA DEL PECCATO


Nel loro storico documento del 1974, "The Protection of Information in Computer Systems",
Jerome Saltzer e Michael Schroeder hanno sposato una manciata di importanti principi di
progettazione; principi che oltre 35 anni dopo sono validi oggi come lo erano allora.
L'ultimo di questi principi è "accettabilità psicologica", che afferma:

È essenziale che l'interfaccia umana sia progettata per la facilità d'uso, in modo che gli utenti applichino
regolarmente e automaticamente i meccanismi di protezione in modo corretto. Inoltre, nella misura in cui
l'immagine mentale dell'utente dei suoi obiettivi di protezione corrisponde ai meccanismi che deve utilizzare, gli
errori saranno ridotti al minimo. Se deve tradurre la sua immagine dei suoi bisogni di protezione in un
linguaggio di specificazione radicalmente diverso, commetterà degli errori.

Nel novembre 2000, Scott Culp, allora ingegnere presso il Microsoft Security Response Center
(MSRC), ha redatto le 10 leggi immutabili dell'amministrazione della sicurezza. La seconda legge
è:

La sicurezza funziona solo se il modo sicuro è anche il modo più semplice.

Troverai collegamenti all'articolo di Saltzer e Schroeder e all'articolo sulle 10 leggi immutabili


nella sezione "Altre risorse" di questo capitolo.
Il modo sicuro e il modo semplice sono spesso in contrasto tra loro. Le password sono un
esempio popolare del modo "facile", ma raramente sono il modo sicuro (vedi Sin 19).
Esiste un'intera disciplina dell'ingegneria dell'usabilità che insegna come creare software più facile
da usare per gli utenti finali. Gli stessi principi di base devono essere applicati anche alla sicurezza.

RIFERIMENTI CWE
C'è solo un riferimento nel dizionario Common Weakness Enumeration:

- CWE-655: Incapacità di soddisfare l'accettabilità psicologica

Sebbene il titolo sia accurato, offre davvero pochissime informazioni sulla debolezza, quindi il
lettore è invitato a leggere le informazioni più approfondite sul sito Web di CWE.

LINGUE INTERESSATE
Questo non è un problema specifico della lingua; è un problema architettonico o di design!

IL PECCATO SPIEGATO
A prima vista, l'usabilità non sembra essere scienza missilistica. Tutti sono utenti e tutti più
o meno sanno cosa è facile da usare per loro. C'è un “non riesco a vedere la foresta
Peccato 14: Povera Usabilità
219

per gli alberi” problema qui, però. I progettisti di software spesso presumono implicitamente che
qualunque cosa trovino utilizzabile, altre persone lo troveranno utilizzabile. Il primo principio per la
creazione di sistemi utilizzabili e sicuri è che "i progettisti non sono utenti". Parleremo di come agire in
base a tale principio nella sezione "Fasi di rimborso".
Allo stesso modo, i designer spesso non sono in sintonia con il livello di fastidio dei loro
utenti. Ad esempio, potresti avere un'applicazione basata sul Web che richiede un nome
utente e una password per ogni connessione. Questo è più sicuro che consentire un
qualche tipo di gestione delle password, in cui vengono ricordate le credenziali dell'utente.
Tuttavia, i tuoi utenti potrebbero trovarlo intollerabile e scegliere un'applicazione in cui i
progettisti non hanno mai fatto un buon lavoro considerando la sicurezza. In seguito a ciò, il
secondo principio per la creazione di sistemi utilizzabili e sicuri è che "la sicurezza non è
(quasi) mai la priorità dell'utente". Ciò che intendiamo con questo è che tutti gli utenti
diranno di volere la sicurezza, ma saranno disposti a rinunciarvi in un attimo se si frappone
a ciò che stanno facendo. Questo è anche il fenomeno che porta le persone a fare clic sulle
finestre di dialogo di sicurezza senza leggerle,
Abbiamo visto questo effetto in Windows Vista; Microsoft ha fatto un ottimo lavoro nel migliorare
notevolmente la sicurezza di Windows, ma gli utenti si sono concentrati solo su un aspetto relativo alla
sicurezza che li ha infastiditi: i prompt UAC (User Account Control) che richiedevano il consenso
dell'utente prima che eseguisse operazioni potenzialmente sensibili. Microsoft ha affrontato bene
questo problema in Windows 7 riducendo drasticamente il numero di prompt e consentendo all'utente
di configurare la quantità di prompt che deve verificarsi.
Dato che la sicurezza non è la priorità dell'utente, dovresti aspettarti che se l'applicazione non è sicura per
impostazione predefinita, l'utente non capirà come renderla sicura. Se l'utente deve premere un interruttore
per ottenere funzionalità di sicurezza, non accadrà. Allo stesso modo, non aspettarti di poter insegnare agli
utenti a essere sicuri istruendoli, nei tuoi manuali o in linea con la tua applicazione. Anche se questo potrebbe
essere un modo semplice per rinunciare alla responsabilità della sicurezza e spostarla sull'utente, non rende il
mondo un posto più sicuro. Quindi ricorda questo: gli amministratori non vogliono modificare le impostazioni
per essere più sicuri e gli utenti normali non hanno idea di come modificare le impostazioni.

Un altro problema comune è che, quando la sicurezza incontra gli utenti, i progettisti spesso
non riescono a rendere le cose ovvie e facili. Ciò lascia gli utenti frustrati e spesso cercheranno
modi per ingannare il sistema per evitare tali frustrazioni. Ad esempio, supponiamo che, in nome
di un'elevata sicurezza, imposti requisiti rigorosi su una password, come un minimo di otto
caratteri con almeno un carattere non alfanumerico, e che la password non sia ovviamente
basata su una parola del dizionario. Che cosa accadrà? Alcuni utenti dovranno provare 20
password prima di ottenerne una accettata dal sistema. Quindi, lo dimenticheranno o lo
scriveranno sotto le loro tastiere. Questo tipo di frustrazione può allontanare i tuoi utenti, in
particolare se rendi la reimpostazione della password anche lontanamente difficile.

Chi sono i tuoi utenti?


Uno dei grandi errori che puoi fare quando pensi (o non pensi) alla sicurezza e all'usabilità è
perdere di vista il pubblico, e nella discussione del peccato, ci concentreremo su due
principali gruppi di utenti: utenti finali e amministratori.
220 24 peccati capitali della sicurezza del software

Gli utenti finali e gli amministratori hanno esigenze diverse quando si tratta di sicurezza e
pochissimi software offrono la sicurezza di cui gli utenti hanno bisogno. Gli amministratori
vogliono assicurarsi di poter gestire i sistemi informatici sotto il loro diretto controllo e i
consumatori vogliono essere al sicuro online. A tal fine, gli amministratori desiderano un facile
accesso ai dati critici che consenta loro di prendere le giuste decisioni in materia di sicurezza. Ma
i consumatori sono diversi: in realtà non prendono buone decisioni sulla sicurezza,
indipendentemente dalla quantità di informazioni che metti loro davanti. In effetti, potremmo
sostenere che per la maggior parte degli utenti non tecnici, meno informazioni tecniche sono le
migliori, ne parleremo un po' di più tra un momento. Non è perché sono stupidi; loro non sono.
(E per favore non chiamare i tuoi utenti "lusers"; queste persone direttamente o indirettamente ti
aiutano a pagare le bollette.
Un aspetto dell'usabilità spesso trascurato è il concetto di usabilità aziendale. Immagina che il tuo
compito sia mantenere 10.000 sistemi che eseguono il tuo software in modo corretto e sicuro. Nessuno
ti aiuterà in questo compito. Molte persone hanno lavori che richiedono loro di amministrare un gran
numero di sistemi e queste persone influiscono sulle decisioni di acquisto, quindi vale la pena essere
gentili con loro.
Ti consigliamo di pensare alla creazione di modi centralizzati per controllare le impostazioni sui sistemi
client, nonché modi per controllare gli elementi di configurazione relativi alla sicurezza. Se devi accedere a
ognuno di quei 10.000 sistemi, sarà una lunga settimana!

Il campo minato: presentazione delle informazioni sulla sicurezza agli utenti


È comune vedere testo e messaggi relativi alla sicurezza che presentano una o più delle
seguenti proprietà:

- Troppe poche informazioni appropriateQuesta è la rovina dell'amministratore:


informazioni insufficienti per prendere la decisione di sicurezza corretta.

- Troppe informazioniQuesta è la rovina dell'utente normale: troppe informazioni sulla sicurezza


che creano semplicemente confusione. Questo è anche un vantaggio per l'attaccante, come
spieghiamo in Sin 11, perché l'applicazione fornisce dati nei messaggi di errore che aiutano
l'attaccante.

- Troppi messaggiAlla fine sia gli amministratori che gli utenti faranno semplicemente clic
sui pulsanti "OK" o "Sì" di fronte a troppi messaggi o disattiveranno la sicurezza del
prodotto in modo che le finestre di dialogo "scompariranno".

- Informazioni imprecise o genericheNon c'è niente di peggio di questo perché


non dice nulla all'utente. Ovviamente, non vuoi nemmeno dire troppo a un
attaccante; è un buon equilibrio.
- Errori con solo codici di erroreI codici di errore vanno bene, purché siano a beneficio degli
amministratori e includano testo per aiutare l'utente.

Ricorda, le persone non esperte di computer prendono decisioni sbagliate sulla fiducia nella sicurezza.
Peccato 14: Povera Usabilità
221

Peccati correlati
Uno dei luoghi in cui la sicurezza e l'usabilità sono più in contrasto tende ad essere nei sistemi di
autenticazione, in particolare nei sistemi di password. Anche quando stai cercando di costruire un
sistema di password sicure (cercando di evitare i problemi di Sin 19), puoi vanificare i tuoi stessi
obiettivi se non consideri l'usabilità.

INDIVIDUARE IL MODELLO DEL PECCATO


Ad alto livello, lo schema qui è un fallimento nell'esplorare il modo in cui l'utente tipico interagirà con le
tue funzionalità di sicurezza. È uno schema in cui cade la maggior parte delle persone, ma può essere
difficile da individuare esplicitamente. In genere cerchiamo di vedere se i progetti hanno uno sforzo
esplicito di ingegneria dell'usabilità e se tale sforzo comprende la sicurezza. In caso contrario,
potrebbero esserci modi per gli utenti di spararsi ai piedi. Questo peccato certamente non è così netto
e secco come molti altri peccati - non è il caso che, se vedi lo schema, ci siano problemi precisi che
aspettano di essere trovati.

INDIVIDUARE IL PECCATO DURANTE LA REVISIONE DEL CODICE


In molti degli altri peccati, raccomandiamo la revisione del codice come tecnica molto più efficace del
test per identificare il peccato. In questo peccato, è proprio l'opposto. Gli individui che usano la propria
intuizione su come l'usabilità e la sicurezza interagiranno probabilmente non scoveranno tutti i
problemi che troverai ottenendo feedback direttamente attraverso le tecniche di test degli utenti.

Ciò non significa che non puoi fare nulla durante il controllo del codice. Significa solo che non
consigliamo di utilizzare la revisione del codice invece di eseguire i test appropriati.
Quando cerchi problemi di usabilità che incidono sulla sicurezza, ti consigliamo di
fare quanto segue:

- Segui il codice dell'interfaccia utente finché non trovi le opzioni di sicurezza.Che cosa è attivato e disattivato per impostazione
predefinita? Se il codice non è sicuro per impostazione predefinita, probabilmente c'è un problema. Potrebbe anche essere

un problema se è facile disabilitare le funzionalità di sicurezza.

- Guarda il sistema di autenticazione.Se l'utente non può autenticare correttamente l'altro lato
di una connessione, esiste comunque un'opzione per accettare la connessione?
Naturalmente, a questo punto l'utente non ha idea di chi si trovi all'altro capo della
connessione. Un buon esempio è una connessione SSL, in cui il software dell'utente si
connette a un server, ma il nome nel certificato dice che il nome del server è qualcos'altro e la
maggior parte degli utenti non se ne accorgerà mai. (Questo è spiegato brevemente.)
222 24 peccati capitali della sicurezza del software

Un'altra cosa che potresti guardare qui è se esiste un modo ovvio per reimpostare una password.
In tal caso, il meccanismo può essere utilizzato per negare il servizio? Coinvolge gli esseri umani nel
ciclo che potrebbe essere suscettibile di ingegneria sociale?

TECNICHE DI PROVA PER TROVARE IL PECCATO


La disciplina dell'ingegneria dell'usabilità ruota intorno ai test. Sfortunatamente, non è lo
stesso tipo di test che le organizzazioni di sviluppo sono abituate a eseguire. Con i test di
usabilità, in genere osservi i tuoi utenti che lavorano in coppia (la tecnica del parlare ad alta
voce a due persone) mentre passano attraverso il sistema, spesso per la prima volta.
Quando cerchi risultati di sicurezza, adotti lo stesso approccio, assicurandoti che l'utente
applichi la funzionalità di sicurezza che ti interessa conoscere.
Di solito è normale dare agli utenti una serie di attività da svolgere, ma non fare nulla per
interferire con ciò che fanno, a meno che non si blocchino completamente.
Le basi dei test di usabilità si applicano sicuramente alla sicurezza e vale la pena raccoglierle.
Consigliamo il libroIngegneria dell'usabilitàdi Jacob Nielsen (Morgan Kaufmann, 1994). Inoltre, il
documento "Usabilità della sicurezza: un caso di studio" di Alma Whitten e JD Tygar offre alcune
buone informazioni sull'esecuzione di test di usabilità per il software di sicurezza. (Vedere la
sezione "Altre risorse" per ulteriori informazioni su queste risorse.)

ESEMPIO PECCATI
Sfortunatamente, non si trovano molti esempi di problemi di usabilità nei bollettini sulla sicurezza. Ciò
è principalmente dovuto al fatto che alle persone piace trasferire la responsabilità di tali problemi
all'utente finale, invece di dare la colpa al software. È più facile per i fornitori passare la responsabilità
all'utente piuttosto che ammettere di mettere a rischio gli utenti.
Tuttavia, ecco un paio dei nostri esempi preferiti del problema.

Autenticazione del certificato SSL/TLS


Ne parliamo in Sin 23. Il problema di base è che, quando l'utente si connette a un sito Web e il
browser Web riceve un certificato non valido o che non sembra avere alcuna relazione con il sito
che l'utente ha tentato di find, il browser genererà tipicamente una finestra di dialogo confusa,
come quella mostrata nella Figura 14-1 da una versione precedente di Internet Explorer.

La maggior parte degli utenti guarderà questo e penserà: "Che diamine significa?" A
loro non importerà, ma vorranno solo accedere al sito web. Faranno clic sul pulsante Sì
senza fare alcuno sforzo per capire il problema. Gli utenti rari, la cui curiosità ha la meglio
su di loro, sceglieranno di fare clic sul pulsante Visualizza certificato e quindi probabilmente
non sapranno cosa dovrebbero cercare.
Per fortuna, questo problema è stato risolto in Internet Explorer 8.0 e versioni successive: la finestra di
dialogo è sparita! Esamineremo questo particolare problema nella sezione "Fasi di rimborso".
Peccato 14: Povera Usabilità
223

Figura 14-1.Finestra di dialogo di Internet Explorer 6.0 durante l'esplorazione di un sito con un certificato autofirmato

Installazione del certificato principale di Internet Explorer 4.0


Prima di Internet Explorer 5.0, se era necessario installare un nuovo certificato dell'autorità di certificazione
(CA) principale perché era necessario accedere a un sito Web utilizzando SSL/TLS e il sito utilizzava la propria
CA (in genere creata con OpenSSL o Microsoft Certificate Server) , allora vedresti la finestra di dialogo
peccaminosa mostrata nella Figura 14-2. (Ora non farci iniziare sui rischi per la sicurezza dell'installazione di
un certificato CA radice da un sito Web che non puoi autenticare. Questa è un'altra storia.)

Figura 14-2.Richiesta di installazione del certificato principale di Internet Explorer 4.0


224 24 peccati capitali della sicurezza del software

Questa finestra di dialogo è pessima perché è totalmente inutile sia per i non geek che per gli
amministratori. Per la persona non crittografata (la maggior parte del pianeta), questo dialogo non significa
assolutamente nulla. E per l'amministratore, i due valori hash sono inutili a meno che tu non sia disposto a
telefonare alla persona o all'azienda che ha creato il certificato e chiedere loro di recitarti gli hash SHA-1 e
MD5 per conferma.
Per fortuna, questo è stato risolto in Internet Explorer 5.0 e versioni successive con una finestra di dialogo
molto più appropriata.

FASI DI RISCATTO
Esistono sicuramente diversi principi di base che è possibile applicare in fase di progettazione
che tenderanno a produrre sistemi più utilizzabili e più sicuri. Esamineremo questi principi qui,
ma ricorda che la tecnica più efficace per combattere questi problemi è il test di usabilità, non la
tua intuizione.

Quando gli utenti sono coinvolti, rendi l'interfaccia utente semplice e chiara
Come discutiamo in questo capitolo, gli utenti dovrebbero essere protetti dall'affrontare la maggior parte dei
problemi di sicurezza. Ma, quando ciò non è possibile (ad esempio, quando è necessario che gli utenti
scelgano o inseriscano password), è necessario comunicare chiaramente con loro, sia per incoraggiare un
comportamento sicuro sia per evitare di frustrarli!
Ad esempio, ripensa a quando abbiamo discusso di come "la sicurezza non è (quasi) mai la
priorità dell'utente". Abbiamo fornito l'esempio di un sistema di password, in cui l'utente deve
fare numerosi tentativi con una password fino a trovarne una che il sistema accetterà.
La nostra preferenza personale è di non imporre troppe restrizioni sulle password, perché in
tal caso le persone tendono a scrivere o dimenticare le proprie password. Ma per quelle
restrizioni che scegli, è molto meglio chiarirle in anticipo. Indica i tuoi requisiti per la password
proprio accanto al campo della password nel modo più semplice possibile. Hai bisogno di un
minimo di otto lettere e un carattere che non sia una lettera? Se lo fai, allora dillo!

Prendi decisioni sulla sicurezza per gli utenti


La maggior parte delle persone non modifica le impostazioni predefinite dell'applicazione. Se consenti loro di eseguire
codice non attendibile e se utilizzi una cifratura di crittografia veloce ma debole per impostazione predefinita, poche
persone metteranno il sistema in uno stato più sicuro in modo proattivo.
Pertanto, è necessario progettare e creare un sistema sicuro per impostazione predefinita. Attiva la
crittografia e l'autenticazione dei messaggi! Se appropriato, abilitare l'autenticazione a più fattori.

Allo stesso tempo, evita di dare all'utente opzioni e scelte eccessive. Questo non solo può indurre
l'utente a scegliere una configurazione meno sicura, ma può anche rendere l'interoperabilità un
problema. Ad esempio, non è necessario supportare ogni suite di crittografia. Un singolo forte che
utilizza l'Advanced Encryption Standard (AES) è abbastanza buono. Mantienilo semplice! La semplicità è
tua amica quando si tratta di sicurezza.
Peccato 14: Povera Usabilità
225

Dovresti anche evitare di coinvolgere l'utente nelle decisioni sulla fiducia. Ad esempio, nella sezione
"Example Sins", abbiamo parlato della convalida del certificato SSL/TLS nei browser Web (in particolare,
quando si utilizza il protocollo HTTPS). Quando la convalida fallisce, l'utente di solito riceve una strana finestra
di dialogo e gli viene chiesto di prendere una decisione di fiducia, una decisione che l'utente generalmente
non è qualificato a prendere.
Cosa dovrebbe essere fatto? L'approccio migliore sarebbe quello di trattare qualsiasi errore nella convalida del certificato come se il sito Web fosse inattivo, e

questo è esattamente ciò che fa Internet Explorer 8. Ciò sposta l'onere di assicurarsi che il certificato sia a posto dall'utente finale al server Web e al proprietario del

certificato, a cui appartiene. In questo scenario, agli utenti non viene chiesto di effettuare chiamate di giudizio tecnico. Se gli utenti non possono accedere al sito a

causa di errori del certificato, non è diverso dal fatto che il sito sia legittimamente inattivo. Ovviamente, devi bilanciare questo e consentire agli utenti di navigare sul

sito se lo desiderano, ma non dopo aver letto un sacco di goo che non capiscono. Questo tipo di interfaccia utente ha l'effetto collaterale di esercitare pressioni sulle

persone del server Web affinché facciano la cosa giusta. In questo momento gli operatori del sito web sanno che possono combinare nomi di certificati e nomi di URL

perché, per impostazione predefinita, nessun browser fallirà la connessione. Se questo cambiasse e il software del client web fallisse sempre la connessione, gli

operatori del server web dovrebbero fare la cosa giusta. È il classico scenario della gallina e dell'uovo. Questa tecnica dovrebbe essere utilizzata anche per le persone

che non vogliono collegarsi a un'infrastruttura a chiave pubblica (PKI) preesistente. Queste persone creeranno i propri certificati, senza alcuna base per fidarsi di quei

certificati. Tali certificati non dovrebbero funzionare a meno che non vengano prima installati come certificati attendibili (radice). gli operatori del server web

dovrebbero fare la cosa giusta. È il classico scenario della gallina e dell'uovo. Questa tecnica dovrebbe essere utilizzata anche per le persone che non vogliono

collegarsi a un'infrastruttura a chiave pubblica (PKI) preesistente. Queste persone creeranno i propri certificati, senza alcuna base per fidarsi di quei certificati. Tali

certificati non dovrebbero funzionare a meno che non vengano prima installati come certificati attendibili (radice). gli operatori del server web dovrebbero fare la

cosa giusta. È il classico scenario della gallina e dell'uovo. Questa tecnica dovrebbe essere utilizzata anche per le persone che non vogliono collegarsi a

un'infrastruttura a chiave pubblica (PKI) preesistente. Queste persone creeranno i propri certificati, senza alcuna base per fidarsi di quei certificati. Tali certificati non

dovrebbero funzionare a meno che non vengano prima installati come certificati attendibili (radice).

Sposta sopra il bastone; Porta la carota


Ma c'è di più nella storia dell'interfaccia utente SSL/TLS; dobbiamo iniziare a insegnare agli utenti le cose
"buone" da cercare. Nel caso di SSL/TLS, i certificati Extended Validation (EV) si sono dimostrati molto utili
perché la barra degli indirizzi nel browser diventa verde quando viene utilizzato un EV valido per identificare
un server web. Dopo aver intervistato 384 acquirenti online, gli esperti di usabilità del computer Tec-Ed
Research hanno pubblicato un rapporto nel gennaio 2007 sull'uso della barra degli indirizzi verde rispetto a
quella non verde:

- Il cento per cento dei partecipanti ha notato quando un sito Web aveva o meno una
barra degli indirizzi URL verde.
- Il novantatre percento dei partecipanti preferisce fare acquisti su siti che hanno la barra degli
indirizzi EV verde.

- Il novantasette percento dei partecipanti condividerebbe i dati della propria carta di credito con siti
che visualizzano la barra degli indirizzi EV verde.

- Il 67% ha affermato che condividerà i dati della carta di credito con o


senza un certificato SSL EV.
- Il 77% ha affermato che ci penserebbe due volte prima di fare acquisti su un
sito Web che ha perso la certificazione EV SSL.
226 24 peccati capitali della sicurezza del software

Se decidi di fornire opzioni che potrebbero ridurre la sicurezza, ti consigliamo di renderle


ragionevolmente difficili da trovare. Cioè, aiuta a impedire agli utenti di spararsi ai piedi! Come
regola generale, l'utente medio non fa clic più di tre volte per trovare un'opzione. Nascondi tali
opzioni in profondità nell'interfaccia utente di configurazione. Ad esempio, invece di avere una
scheda "sicurezza" per il menu delle opzioni, assegna alla scheda "avanzate" un pulsante
"sicurezza". Fai in modo che quel pulsante visualizzi qualcosa che mostra le informazioni sullo
stato, ti consente di configurare la posizione dei registri di sicurezza e fa altre cose innocue.
Quindi, assegna a quella scheda il proprio pulsante "avanzato", dove vivono le cose pericolose. E,
Per favore,accogli quelle opzioni con gli avvertimenti appropriati!

Semplifica l'allentamento selettivo della politica di sicurezza


Ora che hai reso le cose il più sicure possibile per impostazione predefinita, potrebbe essere necessario
introdurre un po' di flessibilità che consenta all'utente di allentare in modo selettivo la politica di sicurezza
senza aprire buchi che il mondo intero può sfruttare.
Un ottimo esempio è il concetto di "barra delle informazioni", una piccola barra di stato aggiunta a
Internet Explorer 6.0 in Windows XP SP2 e versioni successive (e poi adottata da Firefox). Si trova appena sotto
la barra degli indirizzi, informando l'utente delle politiche di sicurezza che sono state applicate. Ad esempio,
anziché chiedere agli utenti se desiderano consentire l'esecuzione di un contenuto attivo o di un codice
mobile, il browser blocca semplicemente l'azione e quindi informa gli utenti che il contenuto è bloccato. A
questo punto, gli utenti possono modificare la politica se lo desiderano, supponendo che dispongano
dell'autorizzazione per farlo, ma l'azione predefinita è l'azione sicura. L'utente non ha preso alcuna decisione
sulla fiducia, il sistema è sicuro, ma il sistema ha informato l'utente di ciò che è accaduto nel caso in cui
qualcosa non avesse funzionato come previsto. La Figura 14-3 mostra la barra delle informazioni.

Indica chiaramente le conseguenze


Quando l'utente si trova di fronte alla decisione di allentare la politica di sicurezza (ad esempio, concedendo
autorizzazioni su una risorsa a qualche altro utente o scegliendo di consentire esplicitamente un singolo
download rischioso), dovresti fare del tuo meglio per chiarire perfettamente quali sono le conse -

Figura 14-3.La barra delle informazioni di Internet Explorer


Peccato 14: Povera Usabilità
227

le sequenze sono! Lo stesso vale se è necessario informare l'utente di un effettivo evento rilevante per la
sicurezza che si è verificato ma non è direttamente collegato alle azioni dell'utente.
Quando si informa l'utente sui rischi, è una cattiva idea utilizzare informazioni eccessivamente tecniche.
Ad esempio, uno dei tanti motivi per cui la finestra di dialogo HTTPS di cui abbiamo discusso in precedenza è
un meccanismo orribile per rilassare la politica di sicurezza è che le informazioni che fornisce sono troppo
confuse. Un altro grosso problema è che non è perseguibile, di cui parleremo tra poco.
Ti consigliamo di fornire un breve messaggio di errore e quindi informazioni più appropriate agli utenti quando
ne hanno bisogno. Questo è chiamatodivulgazione progressiva. Non inondare l'utente o l'amministratore con
informazioni che non possono utilizzare o comprendere; divulgare progressivamente i dati di cui hanno bisogno, se
ne hanno bisogno.
Due buoni esempi sono il modo in cui Internet Explorer e Firefox forniscono informazioni sui
certificati CA radice. La Figura 14-4 mostra la finestra di dialogo utilizzata da Internet Explorer per
visualizzare ed eventualmente installare un certificato. Se desideri maggiori informazioni sul certificato,
di cui francamente solo una persona esperta avrebbe bisogno, fai clic sulle schede Dettagli e/o
Percorso di certificazione. Le schede sono un meraviglioso meccanismo di divulgazione progressiva.

Figura 14-4.Finestra di dialogo Certificato di Internet Explorer


228 24 peccati capitali della sicurezza del software

Rendilo attuabile
Va bene, quindi dici all'utente che è appena successo qualcosa di spaventoso sulla sicurezza. E adesso? C'è
qualcosa che l'utente dovrebbe fare? Forse guardare un file di registro o leggere qualche articolo online?
Aiutare l'utente a risolvere il problema; non lasciarla chiedere: "E adesso?"
Ancora una volta, questo si applica solo quando è assolutamente necessario esporre qualcosa all'utente.

Ripensa al nostro precedente esempio HTTPS. Ok, quindi hai trovato un modo chiaro per dire agli
utenti che il sito che pensavano di visitare non sembra corrispondere al sito che stanno ricevendo
(ovvero, il nome nel certificato non corrisponde). Ora cosa gli dici di fare? Potresti dire agli utenti di
riprovare, ma (indipendentemente dal fatto che il sito sia legittimo o meno) il problema probabilmente
continuerà, almeno per un po'. Potresti consigliare agli utenti di contattare l'amministratore del sito,
ma in molti casi l'amministratore del sito saprà della finestra di dialogo e dirà agli utenti di "fare
semplicemente clic su OK" senza rendersi conto che non possono più distinguere tra il sito reale e un
utente malintenzionato .
In breve, non esiste un modo ovvio per avvisare gli utenti di questa condizione, pur
rendendola perseguibile. Pertanto, probabilmente è meglio non richiamare esplicitamente
la condizione, ma farla sembrare un errore generico, in cui il server è inattivo.

Fornire la gestione centrale


Fornisci un meccanismo, preferibilmente sfruttando le funzionalità del sistema operativo, per gestire la tua
applicazione. Questo è il motivo per cui i criteri di gruppo di Active Directory in Windows sono così popolari e fanno
risparmiare così tanto tempo agli amministratori. Puoi gestire qualsiasi numero di impostazioni a livello di
applicazione e sistema operativo da un'unica console.

ALTRE RISORSE
- “La protezione delle informazioni nei sistemi informatici” di Saltzer e Schroeder:
http://web.mit.edu/Saltzer/www/publications/protection/
- Ingegneria dell'usabilitàdi Jakob Nielson (Morgan Kaufmann, 1994)
- Sito web di ingegneria dell'usabilità di Jakob Nielson: www.useit.com

- Sicurezza e usabilità: progettazione di sistemi sicuri che le persone possono


utilizzarea cura di Cranor e Garfinkel, vari autori (O'Reilly Press, 2005)
- 10 leggi immutabili della sicurezza: www.microsoft.com/technet/archive/
community/columns/security/essays/10salaws.mspx
- “10 Immutable Laws of Security Administration” di Scott Culp:
www.microsoft.com/technet/archive/community/columns/security/
says/10salaws.mspx
Peccato 14: Povera Usabilità
229

- “Sei fastidi di Vista risolti in Windows 7" di Ed Bott: http://


blogs.zdnet.com/Bott/?p=632
- “Esame dei vantaggi per i commercianti che utilizzano un certificato SSL EV”:
www.evsslguide.com/evsslcertificate/step3.html
- “Scrivere messaggi di errore per le funzionalità di sicurezza” di Everett McKay: http://
msdn.microsoft.com/library/en-us/dnsecure/html/securityerrormessages.asp
- “Why Johnny Can't Encrypt: A Usability Evaluation of PGP 5.0” di Alma Whitten e
JD Tyga: www.usenix.org/publications/library/proceedings/sec99/
full_papers/whitten/whitten_html/index.html
- “Usabilità della sicurezza: un caso di studio” di Alma Whitten e JD Tygar:
http://reports-archive.adm.cs.cmu.edu/anon/1998/CMU-CS-98-155.pdf
- “Usabilità e sicurezza sono due direzioni opposte nei sistemi informatici? di
Konstantin Rozinov:
http://rozinov.sfs.poly.edu/papers/security_vs_usability.pdf
- Utilizzare la barra delle informazioni di Internet Explorer:
www.microsoft.com/windowsxp/using/web/sp2_infobar.mspx

- Sicurezza e privacy IEEE, settembre-ottobre 2004: http://


csdl.computer.org/comp/mags/sp/2004/05/j5toc.htm
- Introduzione ai Criteri di gruppo in Windows Server 2003: www.microsoft.com/
windowsserver2003/techinfo/overview/gpintro.mspx

RIEPILOGO
- Farecomprendere le esigenze di sicurezza degli utenti e fornire le informazioni
appropriate per aiutarli a svolgere il proprio lavoro.

- Farerenditi conto che solo perché comprendi un testo di sicurezza, ciò non significa che i tuoi
utenti lo capiscano.

- Fareimpostazione predefinita su una configurazione sicura quando possibile.

- Farefornire un messaggio semplice e di facile comprensione e consentire la divulgazione


progressiva se necessario da parte di utenti o amministratori più sofisticati.

- Farerendere fruibili i prompt di sicurezza.

- Nonscarica il linguaggio geek in una finestra di dialogo che suona il clacson. Nessun utente lo leggerà.

- Nonrendere facile per gli utenti spararsi ai piedi: nascondere le opzioni che
possono essere pericolose!
- Prendere in considerazionefornire modi per allentare la politica di sicurezza in modo selettivo, ma
essere espliciti e chiari su ciò che l'utente sceglie di consentire.
Questa pagina è stata lasciata vuota intenzionalmente
15
Non si aggiorna facilmente

231
232 24 peccati capitali della sicurezza del software

PANORAMICA DEL PECCATO


La maggior parte del software deve essere aggiornata a un certo punto durante il ciclo di vita supportato, che
si tratti di una correzione di bug, di un service pack, di un aggiornamento minore o di correzione di un bug di
sicurezza. Esistono diversi problemi da considerare, a seconda che il software venga utilizzato da utenti
domestici, da utenti aziendali o su server.
Diversi tipi di applicazioni hanno esigenze di aggiornamento diverse. Due esempi estremi sono il
software anti-malware, che potrebbe comportare un aggiornamento ogni pochi giorni, e i giochi
online, in cui c'è una partita a scacchi costante tra alcuni utenti che cercano di imbrogliare e il fornitore
del software che tenta di impedire i cheat per mantenere l'equilibrio del gioco. Se il tuo modello di
minaccia implica il tentativo di impedire agli utenti a livello di amministratore di hackerare i giochi sui
propri sistemi, non possiamo darti molti consigli: l'insieme unico di problemi specifici per gli autori di
giochi online è fuori portata. Anche così, gran parte dei consigli in questo capitolo dovrebbero essere
utili agli sviluppatori di giochi.

RIFERIMENTI CWE
La voce CWE principale qui è "Verifica insufficiente dell'autenticità dei dati", ma molti dei punti deboli
secondari sono pertinenti, in particolare "Affidamento alle ricerche DNS in una decisione di sicurezza".

- CWE-345: verifica insufficiente dell'autenticità dei dati


- CWE-247: affidamento sulle ricerche DNS in una decisione di sicurezza

- CWE-353: Mancata aggiunta del valore del controllo di integrità (anche se questo dovrebbe
essere considerato come mancanza di una firma)

LINGUE INTERESSATE
Questo peccato non è specifico della lingua. Qualsiasi linguaggio di programmazione può essere utilizzato per fornire software
agli utenti.

IL PECCATO SPIEGATO
Questo peccato copre molto terreno; va dal rendere difficile l'applicazione di patch al fatto che gli utenti
vengano hackerati quando provano ad aggiornare il loro software.

Installazione peccaminosa di software aggiuntivo


Gli utenti installano gli aggiornamenti per risolvere i problemi con il software che hanno, non per installare più
software, che potrebbe avere problemi propri. Uno degli esempi più recenti di ciò è stato quando Apple ha
utilizzato il suo meccanismo di aggiornamento per QuickTime per richiedere agli utenti di installare il file
Peccato 15: Non si aggiorna facilmente
233

Navigatore Web Safari. L'installazione di più software aumenta la superficie di attacco dell'utente e,
sfortunatamente per questo esempio, Safari 3.1 presentava un gran numero di gravi falle di sicurezza
subito dopo il rilascio. Un aggiornamento dovrebbe essere qualcosa che l'utente si sente a suo agio
nell'installare automaticamente, senza introdurre nuovo software e potenziali conflitti che ne derivano.

Una leggera eccezione a questa regola è che a volte è necessario introdurre nuove funzionalità in
un service pack o in una versione minore, ma in ogni caso non dovresti mai introdurre software
completamente estraneo. Il momento di chiedere agli utenti se desiderano prodotti aggiuntivi è
durante la configurazione iniziale, sebbene l'autore trovi anche questo fastidioso, anche se fatto dalla
sua stessa azienda!

Controlli di accesso peccaminosi


Diciamo che stai cercando di scrivere un software antivirus. Vorresti richiedere all'utente di installare nuove
firme antivirus e, occasionalmente, installare nuovi eseguibili, che vengono quindi eseguiti con un account
privilegiato. Il modononper fare ciò è necessario impostare le firme e gli eseguibili per consentire a tutti o
all'utente di aggiornarli: nella migliore delle ipotesi un utente malintenzionato può corrompere i tuoi
eseguibili e, nel peggiore dei casi, ciò consente un'escalation di privilegi molto semplice che metterebbe a
rischio tutti i tuoi clienti.

Affaticamento rapido peccaminoso


Se assilli continuamente gli utenti a fare (o non fare) qualcosa, si stancheranno di vedere i
prompt. La nostra esperienza è che in queste condizioni, gli utenti sceglieranno la risposta che fa
scomparire il prompt più rapidamente. A nessuno piace essere assillato tutto il tempo e, come un
collega assillante, i messaggi continui li indurranno a ignorare la fonte e forse si prenderanno
anche la briga di sostituire la fonte dei messaggi! Se un utente ha scelto di non applicare gli
aggiornamenti ora, questa è la sua scelta.

Ignoranza peccaminosa
L'ignoranza può non essere beatitudine. Se sbagli troppo per evitare l'immediato affaticamento,
potresti lasciare l'utente vulnerabile. Se c'è un problema, l'utente deve esserne informato.

Aggiornamento peccaminoso senza notifica


A meno che l'utente non abbia specificamente acconsentito a consentire alla tua app di recuperare e
installare gli aggiornamenti, non uscire e ottenere gli aggiornamenti da solo. Ciò comporterà l'accusa
che la tua app sia davvero un malware, ti metterà nei guai con i clienti che sono sensibili alle
applicazioni che telefonano a casa senza autorizzazione e potrebbe attivare avvisi sui firewall basati su
host.
234 24 peccati capitali della sicurezza del software

Aggiornamento peccaminoso di un sistema alla volta


Immagina di non essere pagato molto bene e di essere responsabile di mantenere attivi e funzionanti
10.000 computer: questa è la situazione reale di molti amministratori di sistema. È appena uscita una
patch critica per il tuo software e non esiste un modo controllato per implementare la patch a livello
centrale. Gli amministratori possono anche ordinare un sacco di pizza: vivranno al lavoro per molto
tempo e saranno molto risentiti per il tuo software.

Forzare peccaminosamente un riavvio


Questo è un problema simile all'ultimo, tranne per il fatto che se riesci a fermare l'applicazione o
il servizio in esecuzione, la patch impiega 30 secondi per l'installazione, ma se il computer deve
riavviarsi, ci vogliono 5 minuti e alcuni dei i sistemi non torneranno correttamente. A meno che tu
non stia aggiornando il sistema operativo, non forzare il riavvio.

Patch peccaminosamente difficile


Se l'utente o l'amministratore deve RTFM (leggere il manuale fine) per applicare la patch, probabilmente non verrà applicata.
Sebbene vada bene per i fanatici dell'alfa, anche richiedere a un utente o ad un amministratore di compilare il codice è
peccaminoso.

Mancanza peccaminosa di un piano di ripresa


Alcune applicazioni possono essere aggiornate solo eseguendo l'applicazione stessa. Avere un'app che
controlla gli aggiornamenti da sola è un'ottima idea, ma se ti capita di creare un bug nel programma di
aggiornamento o se l'app è bloccata e non può essere eseguita, ora non hai un buon modo per recuperare!

Fidarsi peccaminosamente del DNS

Abbiamo scritto un intero capitolo sul non fidarsi del DNS, Sin 24, ma vale la pena ripeterlo qui. Il tuo
software di aggiornamento non deve riporre alcuna fiducia nell'ottenere il server corretto.

Affidarsi peccaminosamente al Patch Server


Quando si ha a che fare con server che si affacciano direttamente su Internet, la domanda giusta non è se il
server web verrà preso in consegna da malintenzionati, maQuandoil server web verrà preso in consegna dai
malfattori e se sarai abbastanza acuto da notarlo! Qualsiasi sistema di consegna delle patch non deve
presumere che qualsiasi passaggio nel processo di consegna che coinvolge reti o server con connessione
Internet debba essere considerato attendibile.

Firma dell'aggiornamento peccaminoso

Ci sono due parti in questo problema. Il primo è semplicemente non firmare affatto l'aggiornamento. Il
secondo è non verificare correttamente la firma. Questo è trattato in dettaglio in Sin 23, "Uso improprio
di PKI, in particolare SSL/TLS".
Peccato 15: Non si aggiorna facilmente
235

Il secondo problema è trattato a lungo in Sin 24, "Trusting Network Name Resolution", ma vale la
pena menzionarlo qui. Ora che ti abbiamo convinto a non fidarti del DNS o del server delle patch e a
firmare i tuoi aggiornamenti, non utilizzare un set obsoleto di algoritmi per firmare le tue patch,
soprattutto non MD5. Le firme MD5 sono completamente rotte e un utente malintenzionato potrebbe
creare malware che corrisponde alla tua patch.
Mentre siamo in tema di firma, firma i tuoi file binari con un server che è tenuto fuori
dalla rete: in primo luogo, non vuoi che la tua chiave privata venga compromessa, e anche
se hai un bel dispositivo hardware per mantenere il privato key safe (consigliato), non vuoi
che persone non autorizzate (dipendenti scontenti o hacker) vadano in giro per la rete
firmando cose a tuo nome.

Disimballaggio dell'aggiornamento peccaminoso

Quindi hai ricevuto il pacchetto di aggiornamento dal server, attraverso la rete e sul disco locale,
e tutto verifica: cos'altro potrebbe andare storto? Se l'aggiornamento è progettato per essere
utilizzato da amministratori o componenti di sistema, è necessario firmare i singoli file eseguibili
oppure decomprimerlo mediante un processo attendibile in un'area attendibile. La directory di
sistema %temp% non funzionerà.

Aggiornamento dell'applicazione utente peccaminoso

Questo è davvero più un problema con l'impostazione iniziale dell'applicazione per iniziare, ma se hai
commesso il peccato di scrivere binari in una directory controllata dall'utente in primo luogo,
probabilmente continuerai a peccare e scrivere aggiornamenti in anche un'area controllata dall'utente.
Ciò consente a qualsiasi app che è stata compromessa a livello di utente di compromettere anche la tua
app e di assicurarsi che rimanga compromessa. La firma non aiuta qui, dal momento che il codice che
controlla la firma è in esecuzione anche a livello di utente e deve essere considerato anch'esso
compromesso.

INDIVIDUARE IL MODELLO DEL PECCATO


A differenza di molti dei peccati in cui cerchi schemi molto specifici nel codice, i seguenti sono il
design generale e le caratteristiche comportamentali di un'applicazione.

- I file consumati da un processo o servizio con privilegi sono scrivibili da utenti senza
privilegi. Se il file è firmato e la firma viene verificata prima dell'utilizzo da parte del
processo privilegiato, non è un problema.
- Esegui un aggiornamento e tenta di installare software aggiuntivo. Se questa è
un'impostazione predefinita, è peggio che suggerire semplicemente nuovo software ogni volta
che correggi i tuoi bug.

- L'app assilla l'utente o va all'estremo opposto e non controlla automaticamente


gli aggiornamenti.

Potrebbero piacerti anche