xplayn > share your experience     
RSS Feed Login     Password        » Registrati «
  
          Home
  Team & Mission
          News
  Development
  Database
          Pubblicazioni
  Articoli
  Tips
  IMHO
          Risorse
  Guide/Manuali/Tools
  Glossario SQLServer
  Collabora con noi
          Blogs
  Maurizio Tammacco
  Francesco Quaratino
  Renzo Pampani
          Formazione
  Database
 
                Partners
      http://www.dotnetside.org
 
 
Pubblicazioni »
Utilizzo "sicuro" di stringhe in .NET 2.0

La classe System.String non rappresenta la soluzione più sicura quando è necessario memorizzare sotto forma di stringa contenuti confidenziali, ad esempio stringhe di connessione a database, password varie, numeri di carta di credito, ecc.. Informazioni di questo genere andrebbero mantenute in memoria solo il tempo strettamente necessario alla loro elaborazione, e la memoria occupata andrebbe rilasciata il più presto possibile. Questo accorgimento è necessario poichè il contenuto della memoria utilizzata da un processo in esecuzione potrebbe essere letta attraverso varie tecniche di hacking, e quindi il suo eventuale contenuto confidenziale correrebbe seri pericoli di manomissione. Inoltre, un processo in esecuzione potrebbe utilizzare un file di swap su disco che provocherebbe la scrittura anche di questo genere di informazioni.

[Perchè una stringa è insicura]
La classe System.String non si adatta affatto a queste caratteristiche. Infatti, una stringa è un oggetto immutabile, per cui ogni modifica ad essa comporta la creazione di una nuova stringa memorizzata in un’area di memoria differente, mentre la vecchia stringa continuerà ad esistere fino alla successiva operazione di garbage collection, che, a causa della sua natura non deterministica, potrebbe avvenire ben più tardi rispetto al momento in cui tutti i riferimenti ad essa sono rilasciati.
L’immutabilità delle stringhe costituisce un serio problema se una stringa contiene informazioni confidenziali per almeno 3 motivi:

• Ogni manipolazione effettuata su di essa lascia in memoria una copia della stessa, in attesa del garbage collector;
• Non esiste alcun modo per “resettare” il contenuto della stringa una volta utilizzato; il tentativo di assegnare un valore nullo provocherà la creazione di un nuovo oggetto stringa con il nuovo contenuto lasciando invariato il vecchio;
• L’indirizzo di memoria in cui è memorizzata una stringa non è costante una volta creata;
• Non è possibile criptare il contenuto di  una stringa senza provocare la creazione di un nuovo oggetto con il contenuto criptato;

[La soluzione in .NET 1.0/1.1]
Nella versione 1.0/1.1 del Microsoft .NET Framework non esiste una soluzione semplice a questo problema. Infatti l’unica strada percorribile è quella di criptare/decriptare manualmente il contenuto di una stringa confidenziale  utilizzando un array di caratteri come area di lavoro. Non è invece possibile resettare una stringa senza attendere che il garbage collector agisca.

[La soluzione in .NET 2.0]
La versione 2.0 del .NET Framework pone rimedio a tutti i problemi di sicurezza precedentemente elencati attraverso la nuova classe SecureString presente nel namespace System.Security.  Questa nuova classe permette di memorizzare in modo sicuro e criptato una stringa contenente contenuto confidenziale, utilizzando DPAPI (Data Protection API), ovvero una serie di API per il criptaggio ed il decriptaggio di informazioni mediante l’algoritmo Triple-DES.

Ecco un esempio di utilizzo:


Come si può notare, l’utilizzo di SecureString è un po’ più macchinoso rispetto alla creazione di un semplice oggetto stringa; infatti esso richiede che la stringa sicura sia costruita aggiungendo un carattere alla volta attraverso il metodo AppendChar(). Il motivo di questo utilizzo dovrebbe essere ovvio: non è possibile costruire una stringa sicura a partire da una stringa già in memoria in testo in chiaro, poiché quest’ultima sarebbe immutabile con gli identici problemi di sicurezza visti precedentemente. Inoltre, una istanza di SecureString è mutabile, il suo indirizzo di memoria non cambia una volta creata e può quindi facilmente essere azzerata attraverso il metodo Clear() senza attendere il garbage collector. Oltre al metodo AppendChar() esistono altri metodi per modificare il contenuto, ad es. InsertAt(), RemoveAt(), SetAt(), il cui nome è abbastanza intuitivo per comprendere il loro utilizzo. La proprietà MakeReadOnly blocca il contenuto dell’oggetto SecureString non permettendo più alcuna modifica. Questa caratteristica può essere letta attraverso la proprietà IsReadOnly. Inoltre, la classe SecureString implementa l’interfaccia IDisposable, ovvero permette al suo utilizzatore di distruggere l’istanza in memoria senza attendere il garbage collector.

Dopo aver creato e popolato una istanza della classe SecureString occorre leggere il valore in essa contenuto. Questa operazione non può essere fatta richiamando semplicemente il metodo ToString() della classe, in quanto quest’ultimo non è stato ridefinito e ritorna semplicemente l’oggetto sotto forma di stringa così come ereditato da System.Object, vale a dire “System.Security.SecureString”, non di grande utilità, e non è semplicissima in quanto comporta una operazione di marshalling (attraverso l’utilizzo della classe Marshal presente nel namespace System.Runtime.InteropServices) che coinvolge l’utilizzo di un puntatore alla stringa, anche se il tutto si risolve con poche righe di codice, come in questo esempio:


Una volta ottenuta la controparte immutabile della stringa, è necessario assicurarsi che l’area di memoria puntata dal puntatore sia azzerata attraverso l’utilizzo del metodo ZeroFreeBSTR della classe Marshal.

[Riferimenti]
[1] Maurizio Tammacco - Pinned object in .NET
[1] Maurizio Tammacco - Uso efficiente delle stringhe in .NET

 
Autore E-Mail Web Site Data
Maurizio Tammacco maurizio@xplayn.org www.xplayn.org 01/06/2006
      ©Copyright 2005 - xplayn.org