
[ Home | Liste | F.A.Q. |
Risorse | Cerca... ]
Archivio: Aprile 2002 ml@sikurezza.org Soggetto: Re: codice corretto, codice robusto, codice sicuro (ver. 3) Mittente: Orlando Onorato Data: 23 Apr 2002 11:52:52 -0000
Rispondo alle tue contestazioni: 1) Un input è valido se è previsto in fase di specifica! Non c'è bisogno di garantirne la sua validità... lo è! Non c'è poi nessun problema di validazione... io definisco valido sono l'input che il committente l'applicazione ha PREVISTO. In altre parole un Input è valido quando è PREVISTO! (Attenzione non si è parlato di Input SICURO!) 2) Un Input non valido è quello non previsto in fase di specifica (capito molto spesso nella pratica). E' vero si potrebbe pensare ad una funzione di validazione che limiti gli input... ma questo verrà dopo, per adesso stiamo dando solo delle definizioni, le soluzioni al problema sarranno affrontate successivamente. 3) Il problema della dimensione dello stato sarà risolto successivamente... ripeto che adesso stiamo dando delle definizioni. Ho accolto con molto piacere le tue obiezioni e spero di poter continuare questa discussione, viste le mie risposte. Tuttavia le cose che ho scritto le ho riviste... ti invio quanto fatto. ________________________________________ 1. Introduzione Il problema della sicurezza è cruciale nel panorama informatico del giorno d 'oggi e vede nella programmazione non sicura le proprie basi. Molti problemi di sicurezza nascono dal fatto che la quasi totalità di sviluppatori di applicazioni software ha sempre scritto e continua a scrivere codice non avendo la "sicurezza in mente". Gli stessi linguaggi di programmazione, il più famoso C, ad esempio, sono stati scritti per rispondere a caratteristiche quali la efficienza, la semplicità, l'usabilità ma non tenendo in considerazione aspetti di sicurezza. Per anni ricercatori ed software house hanno puntato la loro attenzione più nel risolvere i problemi di sicurezza con meccanismi che tentavano di ridurre gli effetti della programmazione non sicura che nel risolvere il problema alla radice. Fortunatamente negli ultimi anni si avuto un cambio di tendenza e sempre più importanza nell'ambito della ricerca sta assumendo il problema della programmazione non sicura. Molti sono i casi di articoli scientifici in cui vengono dettate regole da rispettare per evitare che il software scritto sia soggetto a vulnerabilità conosciute. Tuttavia ancora oggi mancano articoli che trattino la programmazione non sicura in modo sistematico. Le stesse definizioni date di programmazione non sicura appaiono quanto mai ambigue se non, in alcuni casi, contraddittorie. Prima di passare oltre è opportuno riflettere sul fatto che non a caso finora abbiamo sempre parlato di programmazione non sicura e non di programmazione sicura. Questo è dovuto al fatto che la sicurezza è una espressione relativa che non gode di proprietà assolute; in altri termini non è mai possibile dimostrare che una applicazione è in assoluto sicura. E' possibile, tuttavia, dimostrare che essa goda di proprietà che non la rendono soggetta a relative vulnerabilità conosciute. Fatta questa doverosa precisazione, la cui mancanza avrebbe inficiato il rigore del lavoro svolto, con una sorte di abuso di linguaggio parleremo di programmazione sicura, ben avendo in mente la relatività che essa nasconde. 2. Programmazione sicura 2.1 Environment-Application Interaction (EAI) Osservando che molti problemi di sicurezza nascono da una inappropriata interazione tra l'applicazione e l'ambiente in cui essa è eseguita, e che comunque non è possibile definire criteri di sicurezza delle applicazioni prescindendo dall'ambiente in cui esso opera, si è proceduti a distinguere i sistemi in "application" (applicazione) ad "enviroment" (ambiente). I questo modo ogni applicazione sarà vista come una entità che interagisce con un ambiente, di cui fanno parte il software di sistema e le altre applicazioni (Environment-Application Interaction EAI). In base a questa suddivisione diamo le seguenti definizioni.: Definizione (Internal Entity) Ogni elemento del codice di una applicazione e dello spazio dati della stessa, rappresenta una Internal Entitity. Definizione (Internal State) L'insieme dei valori assunti dalle Internal Entity di una applicazione è detto Internal State. Una istruzione è una Internal Entitity. La variabile var di una applicazione, per esempio, è una Internal Entity. Il valore di var è parte dell'Internal State. La dimensione del buffer adoperato per l'Internal Entity var è anch'essa parte dell'Internal State. In generale tutte le informazioni relative al codice ed ai dati di una applicazione, ad esempio stack space, heap space, data space, sono parte dell'Internal State. L'Internal State definisce in pratica la configurazione corrente delle Internal Entitys. Per ogni Internal Entity possono essere prese in considerazione diverse caratteristiche come: un id, il tipo, l' indirizzo di memoria, il valore assunto ecc. Il numero ed il tipo di caratteristiche prese in considerazioni dipendono dalla applicazione in esame e dal tipo di vulnerability che si vuole analizzare. Definizione (Environment Entity) Ogni elemento che è esterno al codice di una applicazione ed al proprio spazio dati è detto Enviroment Entity. Definizione (Environment State) L'insieme dei valori assunti dalle Enviroment Entity di una applicazione è detto Enviroment State. Ad esempio un file è un Evironment Entity. L'esistenza di un file, i permessi su un file sono invece parte dell'Enviroment State. Considerazioni analoghe all'Internal State possono essere fatto all'Environment State. Definizione (Global State) Si definisce Global State il risultato di una funzione che dipendente dall'Internal State, dell'Environment State e dell' Input. Esso può assumere i valori valido ed invalido. Global State = function ( Internal State, Environment State, Input) Un Global State invalido è anche detto Vunerability. Elemento chiave per la programmazione sicura sono i Global State. Si rendono quindi necessarie alcune precisazioni per meglio comprendere il loro significato e valore. Incominciamo con chiarire che l'Internal State ed l'Environment State, la cui unione da luogo al Global State, non sono incorrelati, anzi è la loro congiunzione che rende un Global State valido o meno. Per questo motivo una applicazione è ritenibile sicura (Global State valido) in un ambiente e non in un'altra. Esistono inoltre più Global State validi che scaturiscono da combinazioni diverse di Internal State ed Environment State. 2.2 Programmazione corretta, robusta e sicura Sempre più spesso si confonde la programmazione sicura con quella robusta creando atteggiamenti e metodologie che non consentono di affrontare il problema della sicurezza in modo efficace. In questo paragrafo saranno date le definizioni di programmazione corretta, programmazione robusta e programmazione sicura e verranno analizzate le relative differenze al fine di sgombrare il campo da qualsiasi ambiguità. Suddividiamo l'Input, l'Output ed il Global State di una applicazione in "valido" ed "invalido", dove per validità si intende la coerenza con le specifiche date, e per Input non solo quelli forniti dall'utente ma anche quelli ricevuti da altre applicazioni. Definizione (Programma corretto) Un programma è corretto se si comporta come previsto dalle proprie specifiche; in altre parole un programma è corretto se, sottoposto ad input validi, fornisce output validi. Definizione (Programma robusto) Un programma è robusto se, sottoposto ad input validi e/o invalidi, comunque fornisce output validi. Questo significa che un programma robusto dovrà fornire output coerenti con le specifiche anche se sottoposto ad input imprevisti. La nozione di robustezza di un programma non ha una definizione che indichi precisamente cosa si debba fare per ottenere software robusto. Da un programma robusto ci si aspetta che sia corretto ma che sia in grado di comportarsi correttamente anche in presenza di situazioni non previste dalle specifiche. Definizione (Programma sicuro) Un programma è sicuro se, sottoposto ad input invalidi e/o validi, si porta sempre in un Global State valido. Il fatto che il programma sia sempre in uno Global State consente di evitare comportamenti anomali, volutamente o involontariamente prodotti, che possono, in un modo o in un altro, consentire al programma di eseguire operazioni non desiderate. Non viene fatto nessuna ipotesi sul rapporto input/output e quindi sulle funzionalità dell'applicazione. figura 1 - applicazione corretto, robusto, sicuro. Le definizioni date rendono chiare le seguenti implicazioni: · una applicazione robusta è anche corretta; · una applicazione non sicura potrebbe comportarsi in modo corretto e robusto; · una applicazione sicura potrebbe essere non corretta e non robusta; · una applicazione sicura in un ambiente potrebbe non esserlo in un'altra. In altre parole non c'è alcun legame diretto tra la robustezza/correttezza di una applicazione e la sua sicurezza. Tuttavia è opportuno osservare che la definizione data di applicazione sicura presuppone che l'applicazione stessa reagisca ad input validi o/e invalidi in modo da portarsi sempre in uno stato valido. Quando questo è possibile contrasta con requisiti di efficienza e complessità; quando non è possibile contrasta con i requisiti di funzionalità in quanto alcuni input e/o output non possono essere gestiti e quindi accettati dall'applicazione in quanto porterebbero la stessa, inevitabilmente, in uno Global State non valido. Meritevole di nota è poi la scelta di distinguere il Global State di un sistema in valido e/o invalido e non in sicuro e/o non sicuro. Siccome una applicazione è sicura se il suo Global State è valido potrebbe sembrare più opportuno parlare di Global State sicuro e/o non sicuro; questa scelta tuttavia nasconderebbe una ambiguità di fondo. Uno Global State non è mai sicuro di per sé ma lo è in riferimento ad una specifica applicazione (vedi paragrafo successivo). Pare quindi più corretto parlare di Global State valido che di Global State sicuro. Nei capitolo successivi saranno analizzate le vulnerabilità più comuni e definite per ognuna di esse uno Global State valido. .questo mi consentirà di procedere in modo schematico definendo per ogni vulnerabilità (security risk) un proprio stato valido! 2.3 Programmazione corretta e/o robusta vs. Programmazione sicura Analizziamo in questo paragrafo quali siano le conseguenze, in termini di approccio metodologico, tra la programmazione sicura e quella corretta e/o robusta. Appare chiaro che nella programmazione corretta e/o robusta il lavoro del programmatore è tutto rivolto allo sviluppo delle funzionalità definite in fase di specifica; in altre parole si programma tenendo in mente cosa il programma deve fare. Nelle programmazione sicura le cose cambiano; in fase di specifica occorre definire gli stati validi; questi vengono individuati in modo da garantire che il programma non esegue, in modo più o meno volontario, azioni non desiderate. Ecco quindi che viene introdotto nella programmazione un aspetto fin'ora mai considerato: bisogna programmare tenendo in mente non solo cosa il programma deve fare ma anche cosa non deve fare! Questo cambiamento di atteggiamento alla programmazione definisce quella che comunemente viene chiamata: security risk, ossia l'analisi dei rischi alla sicurezza a cui un programma in esecuzione è esposto, o espone il sistema su cui viene eseguito. E' dall'analisi dei rischi che scaturiscono poi i Global State validi di una applicazione. 2.4 Evitare Global State invalidi Una volta definiti i Global State invalidi quali tecniche si possono adoperare per evitare che essi vengano raggiunti da una applicazione? Analizziamo i casi in cui l'Input fornito alla applicazione conduce la stessa in un Global State invalido: 1) indipendentemente dall'Environment State. 2) indipendentemente dall'Internal State. 3) in funzione dell'Environment State e dell'Internal State. 4) Indipendentemente dall'Environment State e dall'Internal State. 2.4.1 Global State Invalido indipendentemente dall'Environment State In questo caso: Global State = function ( Internal State, Input) Qualsiasi sia l'ambiente in cui l'applicazione è eseguita esistono Input tali che rendono il Global State invalido, ed esso non dipende dal Environment State. Diciamo sin dall'inizio che una situazione del genere non solo è sperabile ma è da ricercare. Scrivere applicazioni la cui sicurezza è indipendente dall'Environment State consente di scrivere e testare applicazioni sicure in modo più semplice; in altre parole tutto ciò che influisce sulla sicurezza è in nostro pieno possesso. Analizziamo adesso tutte le possibili situazioni. Se si verifica una situazione del genere: per ogni Input: Global State = invalido l'unica soluzione è quella di modificare l'applicazione; non esiste altro rimedio. Se invece si ha: esistono Input: Global State = invalido allora si possono adottare sostanzialmente due strategie: 1) Evitare che gli input che rendono il Global State invalido non vengano forniti all'applicazione, ad esempio mediante funzioni di validazione degli Input. Siccome questi porterebbero sicuramente l'applicazione in uno Global State invalido potrebbe essere conveniente adoperare una politica di questo tipo. Tuttavia è opportuno osservare che questa potrebbe influire notevolmente sulle funzionalità della applicazione. 2) Modificare l'applicazione in modo da evitare di portarla in un Global State invalido quando sottoposta a questi Input. E' opportuno notare che in questo caso bisogna accertarsi di trovarsi ancora nel caso in esame (indipendenza dell'Environment State). Una situazione certamente desiderabile è quella in cui: per ogni Input: Global State = valido in questo caso potremmo dirci certi che la nostra applicazione è sicura. Osserviamo però che una situazione del genere è quanto mai rara, non fosse altro che per la necessità di una analisi esaustiva sugli Input possibili. 2.4.2 Global State Invalido indipendentemente dall'Internal State In questo caso: Global State = function ( Environment State, Input) esistono Input tali che rendono il Global State invalido, ed esso non dipende dall'Internal State. Le considerazioni fatte nel paragrafo 2.4.1 possono essere estese a questa situazione. 2.4.3 Global State Invalido in funzione dell'Internal State e dell' Environment State In questo caso: Global State = function ( Internal State, Environment State, Input) esistono Input tali che rendono il Global State invalido, ed esso dipende sia dall'Internal State che dall'Environment State. In questo caso le strategie che si possono adoperare sono: 1) l'inserimento dell'input non porta inevitabilmente ad un Global State invalido; questo dipende dalla combinazione dell'Internal State e dell' Environment State. Questo significa che la validazione dell'input potrebbe essere un prezzo troppo caro da pagare a fronte di un evento poco frequente. In questo caso occorrerebbe un monitor che verifichi il Global State e quando invalido (o meglio prima che diventi invalido) esegue le dovute azioni; tuttavia questa soluzione prevede un controllo runtime che potrebbe inficiare la efficienza della applicazione. 2) è possibile che modificando l'applicazione stessa si determini una condizione per cui il Global State non diventi mai invalido. 2.4.4 Global State Invalido indipendentemente dall'Internal State e dall' Environment State In questo caso: Global State = function ( Input) Le soluzioni possibili sono: 1) Evitare l'inserimento degli Input che rendono il Global State invalido (funzione di validazione). In questo caso èssa risulta quanto mai necessaria siccome l'inserimento di questi Input porterebbero inevitabilmente ad una vulnerability. 2) Modificare l'applicazione cercando di portarsi in altri casi. _________________________________________ ----- Original Message ----- From: "Saverio Salatino" <ssalatino@supereva.it> To: <ml@sikurezza.org> Sent: Tuesday, April 23, 2002 10:30 AM Subject: Re: codice corretto, codice robusto, codice sicuro (ver. 2) > Orlando Onorato scrive: > > Definizione (Programma corretto) Un programma ? corretto se si comporta come > > previsto dalle proprie specifiche; in altre parole un programma ? corretto > > se, sottoposto ad input validi, fornisce output validi. > > Cosa ti garantisce la validit? di un input? Non ? detto che in un ambito teorico, > ed avendo un programma che non sia propriamento stupido (ovvero assimilabile > ai modelli di automi a stati finiti o automi a pila), ogni input sia validabile o > meno (Problema della fermata di Turing). > > > Definizione (Programma robusto) Un programma ? robusto se, sottoposto ad > > input validi e/o invalidi, comunque fornisce output validi. Questo significa > > che un programma robusto dovr? fornire output coerenti con le specifiche > > anche se sottoposto ad input imprevisti. La nozione di robustezza di un > > Sembra parlando di modelli puramente teorici in input non valido, se riconosciuto, > non dovrebbe essere accettato, uscendo quindi con un opportuno messaggio di errore. > > > Definizione (Programma sicuro) Un programma ? sicuro se, sottoposto ad input > > invalidi e/o validi, l'internal state e l'environment state sono validi. Il > > Qua si passa decisamente ad un livello pi? pratico, per cui tenendo conto > della numeor di possibili stati (finiti) assumibili da un ambiente reale, > sarebbe, con notevole spreco di risorse, generare l'output completo > delle possibile risposte ad ogni singola domanda "presentabile" ad un programma ... > Vi lascio immaginare la semplicit? della verifica gi? con un numero di input > possibili pari a 2^16 (giusto per dire tenerci mooooolto bassi). > Senza tenere conto (ma di questo non mi intendo assolutamente) che il nostro > codice di alto livello raramente ? l'esatta rapressentazione di quello che verr? > eseguito a livello macchina, per cui bisognerebbe compiere l'analisi sul codice > generato dal compilatore, e non su quello di alto livello da noi scritto. > > > Non so se tu abbia gi? discusso o meno la tua tesi, ma ad occhio quelle sopra > potrebbero essere delle obiezioni che ti potrebbero essere mosse in fase di discussione. > Buon lavoro > > Saverio Salatino > > ________________________________________________________ > http://www.sikurezza.org - Italian Security Mailing List > ________________________________________________________ http://www.sikurezza.org - Italian Security Mailing List
[ Home | Liste | F.A.Q. |
Risorse | Cerca... ]
www.sikurezza.org - Italian Security Mailing List
(c) 1999-2005