Alkampfer's Place

Il blog di Gian Maria Ricci
posts - 659, comments - 871, trackbacks - 80

My Links

News

Gian Maria Ricci Mvp Logo CCSVI in Multiple Sclerosis

English Blog

Tag Cloud

Article Categories

Archives

Post Categories

Image Galleries

I miei siti

Siti utili

Rendere sicure le proprie querystring

Nelle proprie applicazioni ASP.Net la querystring è un modo comodo per passare parametri tra le pagine, questo spesso però può rendere la propria applicazione poco sicura. Il problema è che spesso questa tecnica viene usata per specificare id o dati similari, ad esempio si mostra una pagina con una lista di oggetti e poi premendo un link di dettaglio si viene mandati ad esempio alla ShowDetail.aspx?id=34. Un attaccante può naturalmente provare a sostituire al valore 34 altri valori ed avere accesso magari a oggetti a lui non permessi. Solitamente la propria applicazione dovrebbe quindi fare un controllo accurato sui parametri di querystring per evitare problemi di sicurezza. Una soluzione che rende il tutto più sicuro è quella di utilizzare la UrlRewriting per criptare la querystring. Prima di tutto inserire nel proprio web.config le chiavi crittografiche da utilizzare. (In una situazione più sicura le chiavi non andrebbero nel web.config)

<add key="QueryStringEncryptionKey" value="E26AABA4745F…"/>
<add key="InitializationVector" value="C6571078191F67093117D76CFD8B9A40"/>

Ora si crea una semplice funzione a cui verrà passata la stringa rappresentante il querystring e che restituisce un nuovo querystring cifrato

public static String EncodeQueryString(String queryString) {
   
MemoryStream ms = new MemoryStream();
   
RijndaelManaged crypto = new RijndaelManaged();
   
ICryptoTransform ct = crypto.CreateEncryptor(
      
HexEncoding.GetBytes(ConfigurationManager.AppSettings["QueryStringEncryptionKey"]),
      
HexEncoding.GetBytes(ConfigurationManager.AppSettings["InitializationVector"]));
   
CryptoStream cs = new CryptoStream(ms, ct, CryptoStreamMode.Write);
   
Byte[] rawQueryString = Encoding.ASCII.GetBytes(queryString);
   cs.Write(rawQueryString, 0, rawQueryString.Length);
   cs.Close();
   
return "ck=" + HttpContext.Current.Server.UrlEncode(Convert.ToBase64String(ms.ToArray()));
}

La cifratura scelta è la AES, la chiave e l'initialization vector sono tenuti nel web.config, la funzione di cifratura è standard e l'unica particolarità è la classe HexEncoding che ho preso dal libro "Developing more secure asp.net 2.0" che converte da una rappresentazione esadecimale stringa ad un array di byte, ma la sua implementazione è veramente banale. A questo punto si fa un HttpModule che elabora la BeginRequest e che automaticamente controlla se nella querystring è presente la chiave ck indice del fatto che è stata passata una querystring cifrata

public void Application_BeginRequest(object sender, System.EventArgs args) {
   
if (HttpContext.Current.Request.QueryString["ck"] != null) {
      
String criptedQueryString = HttpContext.Current.Request.QueryString["ck"];
      
Byte[] rawQueryString = Convert.FromBase64String(criptedQueryString);
      
MemoryStream ms = new MemoryStream();
      
RijndaelManaged crypto = new RijndaelManaged();
      
ICryptoTransform ct = crypto.CreateDecryptor(
         
HexEncoding.GetBytes(ConfigurationManager.AppSettings["QueryStringEncryptionKey"]),
         
HexEncoding.GetBytes(ConfigurationManager.AppSettings["InitializationVector"]));
      
CryptoStream cs = new CryptoStream(ms, ct, CryptoStreamMode.Write);
      cs.Write(rawQueryString, 0, rawQueryString.Length);
      cs.Close();
      
String decryptedQueryString = Encoding.ASCII.GetString(ms.ToArray());
      
HttpContext.Current.RewritePath(HttpContext.Current.Request.Path + "?" + decryptedQueryString);
   }
}

Grazie al metodo RewritePath della httpcontext è possibile modificare il path della richiesta in modo che le pagine non si accorgano nemmeno della cifratura della querystring, ecco infatti una pagina in azione.

protected void Page_Load(object sender, EventArgs e) {
   
foreach(String key in Request.QueryString.AllKeys) {
      Response.Write(key + 
"=" + Request.QueryString[key] + "<BR />");
   }
}
 
protected override void OnPreRender(EventArgs e) {
   
String querystring = "a=pippo&b=pluto";
   HyperLink1.NavigateUrl = 
"/SecureQueryString.aspx?" + QueryStringSecure.EncodeQueryString(querystring);
   
base.OnPreRender(e);
}

Come si può vedere nell'OnPreRender si crea un link per un oggetto hyperlink, notate come la querystring sia prima preparata e poi cifrata dal metodo Statico EncodeQueryString del mio modulo. Il link cosi generato è: http://localhost:49998/SecureQueryString.aspx?ck=3TOZStpI8jIkeoCOEjfoVQ%3d%3d e come potete vedere è ora impossibile per il chiamante giocherellare con i parametri di querystring per cercare di trovare qualche falla nella vostra applicazione anche perché se non si è in possesso delle chiavi crittografiche giuste non si può manipolare in nessun modo la querystring. Nel load viene invece effettuato un dump dei parametri che si trovano nella querystring per verificare che effettivamente i dati ricevuti siano quelli attesi.

Naturalmente non dimenticate di proteggere le chiavi del web.config con aspnet_regiis o con aspnet_setreg.

Alk.

Print | posted on lunedì 8 ottobre 2007 11:26 | Filed Under [ .NET ]

Feedback

Gravatar

# re: Rendere sicure le proprie querystring

Complimenti, una soluzione semplice ed elegante.

Tuttavia merita una considerazione, che un pò si riaggancia a tutti i discorsi di sicurezza fatti e mostrati nei giorni (tempi) passati il cui ultimo esempio lo abbiamo visto con il post di Raffaele.
Arrivare ad una criptazione significa che si stanno esponendo talmente tanti parametri sulla querystring da invitare l'utente giocherellone.

Se invece, come spesso purtroppo non accade, si facesse una buona progettazione (invece che campare con , sicuramente non ci sarebbero tonnellate di informazioni "esposte". Immaginati una querystring dove al massimo passi un id ... o dove alcune informazioni necessarie le incameri nella fase di pre-post utilizzando sistemi alternativi (cookie, piuttosto che campi form nascosti popolati via js).
Insomma di soluzioni ce ne sono tante, e sicuramente la tua è una soluzione che merita più di altre. Del resto l'informatica è "una soluzione".
08/10/2007 13:42 | Andrea
Gravatar

# re: Rendere sicure le proprie querystring

BEne, sono contento di vedere commenti che fanno domande. Cerchiamo di rispondere un po
Se l'utente scombina viene generata una eccezione perchè lo stream non riesce ad essere decrittato.
Performance, le pagine ASP sono multithread, per cui si sfruttano tutti i core, non è una operazione di IO che potrebbe essere fatta asincrona.
Le operazioni di cifratura e decifratura nel mio progetto sono nella stessa classe, la cifratura è un metodo statico del modulo, e con una variabile inizializzata nell'evento init capisco se è stato attivato o meno dal web.config.
@andrea. Al 100% sono daccordo con te, sempre meglio strutturare bene l'applicativo dall'inizio, ma questa è una buona tecnica che funge anche da "toppa" :D ovvero tu hai un app dove i controlli sull'imput sono ZERO...invece che riscrivere tutto ... :D
Cmq, (mi pare che Dino Esposito, avesse scritto un articolo) si deve mettere in piedi una infrastruttura che comunque e sempre valida passando al setaccio gli ijnput utente di querystring e form, ad esempio specificando i parametri validi, una regular expression e comunque facendo sempre il tutto pensando che dall'altra parte ci sono orde di orchi che tentano di fare del male alle nostre pagine

Alk.
08/10/2007 17:15 | Gian Maria
Gravatar

# re: Rendere sicure le proprie querystring

Bellissimo post. Grazie!
09/10/2007 02:15 | Alessio Marziali
Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET