360 likes | 463 Views
"Non esiste una patch per la stupidità" http://www.sqlsecurity.com. ASP.NET Security. Raffaele Rialdi MVP.NET malta@vevy.com http://mvp.support.microsoft.com MVP Profile: http://snipurl.com/7vyf. Agenda. Spoofing / Tampering. Spying. Sql/script Injection. D.O.S. Autenticazione
E N D
"Non esiste una patch per la stupidità" http://www.sqlsecurity.com ASP.NET Security Raffaele Rialdi MVP.NET malta@vevy.com http://mvp.support.microsoft.comMVP Profile: http://snipurl.com/7vyf
Agenda Spoofing / Tampering Spying Sql/script Injection D.O.S. Autenticazione ("chi sei?") Autorizzazione ("cosa posso fare?") IIS • Anonymous • Basic • Windows • Certificate • NTFS Access Control List (ACL) Asp.net.aspx, .asmx, .asax, .ascx, .soap, .rem, ... • UrlAuthorizationModule • FileAuthorizationModule • None • Windows • Forms • Passport Web Application • Imperative • Declarative NTFS LDAP SQL
Meccanismi diAutenticazione • IIS • Anonima • Basic • Digest • Certificate • Windows • Asp.net • Passport • Forms
Windows Authenticationstep-by-step • Web.config di default è pronto: • Impostare le autorizzazioni • Disabilitare l'autenticazione anonima in IIS ... (prossime slide) • L'utente autenticato è: (stringa vuota se anonimo) • L'utente usato dal worker process è: <authentication mode="Windows" /> <authorization> <deny users="?" /> <allow users="*" /> </authorization> ? utente anonimo * tutti gli utenti HttpContext.Current.User.Identity.Name System.Security.Principal.WindowsIdentity.GetCurrent().Name
Impersonation(solo con Windows Authentication) • Il token di security a livello di thread viene sostituito con quello dell'utente autenticato.Il token di processo rimane invariato. • Se l'utente è anonimo, viene impersonato IUSR_NomePc • Sintassi (web.config): <identity impersonate=true /> • IIS5 non può eseguire più worker process sotto identità diverseSoluzione: impersonation di un utente specifico<identity impersonate=true user="xxx" password="zzz" />
I problemi architetturalidi Impersonation Molti vogliono usare la security di Sql server • Se il db è in rete, impersonation non funziona ma ci vuole invece delegation • Si perde il controllo centralizzato della security(accedere a Ntfs, Ldap, risorse in rete, DB) • La security 'per righe' fatta con sql server è un incubo
I problemi tecnologicidi Impersonation • Il token dell'utente non può essere usato per accedere a risorse remote (per es. la webapp non può usarlo per accedere un db in rete)La soluzione viene con Delegation che è di default disabilitata (proprio perchè è pericolosa!) • Impersonation implica contesti diversi per ciascun utente. Questo significa niente connection pooling • Protezione limitata. Un eventuale buffer overrun può usare sia il token di thread (impersonato) che quello di processo (worker process) usando RevertToSelf. • Se chiamo un componente COM che sta in un apartment diverso, COM non userà il token di impersonazione ma quello di processo
Forms Authenticationstep-by-step • Abilitare l'autenticazione anonima in IIS • Impostare l'autenticazione e i suoi parametri • Impostare le autorizzazioni • Creare la pagina di login controllare l'utente e autorizzarlo <authentication mode="Forms"> <forms name="myCookieName" loginUrl="~/Login.aspx" /> </authentication> <authorization> <deny users="?" /> <allow users="*" /> </authorization> ? utente anonimo * tutti gli utenti if(UserDB.Check(txtUsername.Text, txtPassword.Text)) { FormsAuthentication.RedirectFromLoginPage( txtUsername.Text, ckRemember.Checked); }
Forms Authenticationgestire i ruoli • Gestire l'evento Application_AuthenticateRequest • Impostare le autorizzazioni per singole parti del sito protected void Application_AuthenticateRequest(Object sender, EventArgs e) { UserDB.AssignRoles(); } <location path="Backoffice.aspx"> <system.web> <authorization> <deny users="?" /> <allow roles="admins" /> <deny users="*" /> </authorization> </system.web> </location> L'ordine di valutazione delle autorizzazioni è dal primo verso l'ultimo. Il primo 'match' vince.
Forms AuthenticationGestione utenti e ruoli • Si costruisce una piccola classe: public class UserDB { public static bool CheckUser(string Username, string Password) { return (Username == Password);// Solo per la demo!!! ;-) } public static void AssignRoles() { IPrincipal CurrentUser = HttpContext.Current.User; if(CurrentUser != null && CurrentUser.Identity.IsAuthenticated && CurrentUser.Identity.AuthenticationType == "Forms") { string User = CurrentUser.Identity.Name; string [] roles = GetRolesForUser(User); CurrentUser = new System.Security.Principal.GenericPrincipal (CurrentUser.Identity, roles); } } private static string[] GetRolesForUser(string User) { string[] roles = new string[2]; roles[0] = "Administrators"; roles[1] = "Users"; return roles; // Solo per la demo! } }
Principal e IdentityLa sicurezza basata sui ruoli secondo il framework • IIdentity rappresenta l'identità di un utenteWindowsIdentity, FormsIdentity, PassportIdentity, GenericIdentity • IPrincipal contiene l'Identity e i ruoliWindowsPrincipal, GenericPrincipal • String. "Windows", "Forms", "Passport", ... • Bool. Indica se l'utente è autenticato • String. Nome dell'utente AuthenticationType IsAuthenticated Name • IIdentity. • Bool. Indica se l'utente appartiene ad un certo ruolo (gruppo) Identity IsInRole
Forms AuthenticationGestione utenti • Gli utenti si possono anche gestire nel web.config ma è sconsigliato: <authentication mode="Forms"> <forms name="myCookieName" loginUrl="~/Login.aspx"> <credentials passwordFormat = "SHA1" <user name="UserName1" password="SHA1EncryptedPassword1"/> </credentials> </forms> </authentication>
Forms AuthenticationTip • Diciamo di avere due Web Application ... • Prendiamo in considerazione: • Nome del cookie della Forms authentication • Path del cookie • Il tag <machineKey ... /> nel web.config(vedi http://support.microsoft.com?id=312906) • Se sono identici, l'utente potrà navigare da una all'altra senza doversi ri-autenticare • Se almeno uno di questi è diverso, sarà necessario ri-autenticarsi
Autenticazione mistaWindows / Forms Il problema: • In Windows Authentication, l'header HTTP "LOGON_USER" contiene il nome utente • Se IIS è configurato come anonimo, NON viene passato il nome utente anche se siamo loggati sul dominio • ... Ma la Forms authentication richiede che IIS sia configurato come anonimo(altrimenti compare la dialog di autenticazione)
Autenticazione mistaWindows / Forms La soluzione: • Due pagine di Login: Forms e Windows • Web.config configurato per la Forms • Autorizzazione a tutti per la pagina di Login Windows • IIS – WebApp: abilitare accesso anonimo • IIS – LoginWin.aspx: togliere accesso anonimo • LoginWin.aspx: Crea il ticket della Forms authenticaion a partire dalle credenziali Windows <location path="LoginWin.aspx"> <system.web> <authorization> <allow users="*" /> </authorization> </system.web> </location>
Forms Authenticationcon LDAP • LDAP è un protocollo per dialogare con Active Directory • Posso chiedere con LDAP: • di verificare le credenziali di un utente su AD • di darmi l'elenco dei gruppi a cui appartiene quell'utente • Il codice per fare queste due cose è qui:http://support.microsoft.com/?id=326340 • Metodo 1: Public Function IsAuthenticated(ByVal domain As String, ByVal username As String, ByVal pwd As String) As Boolean • Metodo 2: Public Function GetGroups() As String • Un ottimo motivo per usarla è nelle WebApp con autenticazione mista Windows + Forms
Dove siamo? Autenticazione IISBasic, Win, ... Asp.netPassport, Form Raffaele Pagina si/no Autorizzazione IISNTFS Asp.net<authorization ... /> Codice si/no Controllo Imperativo Controllo dichiarativo Asp.netPrincipalPermission, etc.
Sicurezzaimperativa e dichiarativa • Gli attrezzi del mestiere: • IPrincipal.IsInRole() Imperativa (bool) • PrincipalPermission.Demand() Imperativa (SecurityException) • PrincipalPermissionAttribute Dichiarativa (SecurityException) if(User.IsInRole("Admins")) { ... } PrincipalPermission perm = new PrincipalPermission(null, "Admins"); perm.Demand(); PrincipalPermissionAttribute [PrincipalPermission(SecurityAction.Demand, Role="Admins")] public void MyAdminMethod() {...}
Mai dare informazioni preziosedefault: <customErrors mode="RemoteOnly" /> • Qualsiasi informazione sugli errori può essere sfruttata da un hacker. • Gli errori custom (che nascondono i dettagliati): • mode="Off" mostrati a nessuno • mode="On" mostrati a tutti • mode="RemoteOnly" solo in remoto • Questo meccanismo è poco elastico • Possiamo usare un HttpModule per migliorare la situazione ....
CustomErrorHandler(esempio) • Web.Config:<customErrors mode="On" defaultRedirect="~/HttpErrors.aspx" />.... <httpModules> <add type="CustomErrorHandler.RafErrorModule, CustomErrorHandler" name="RafErrorModule"/></httpModules> • Due pagine di gestione errore:SoftError.aspx (per utenti) e HardError.aspx (per admin) • Il Module redirige gli errori a seconda del ruolo dell'utente • Il Module gestisce gli errori Http e le Exception ... vediamo il codice ...
SQL Injection • Un pirata può devastare il db ... string strSql = "Select * from authors where au_lname like '" + TextBox1.Text + "'"; SqlCommand cmd = new SqlCommand(strSql, Cnn); SqlDataReader dr = cmd.ExecuteReader(); Select * from authors where au_lname like ' ' ; drop authors - - ' Prima query Seconda query Scartato
SQL Injection... usare i parameters!!! ... • I Parameters incrementano anche le performance: • non c'è conversione da string a tipo sul db • la query rimane compilata e preparata sul db server string strSql = "Select * from authors where au_lname like @au_lname"; SqlCommand cmd = new SqlCommand(strSql, Cnn); cmd.Parameters.Add("@au_lname", SqlDbType.VarChar,40); SqlDataReader dr = cmd.ExecuteReader(); exec sp_executesql N'Select * from authors where au_lname like @au_lname', N'@au_lname varchar(40)', @au_lname ='' ' ; drop authors - - ' apice raddoppiato da ADO.NET Gli apici non sono l'unico problema:select * from titles where royalty = 0 ; drop authors
XSS: Cross Site Scripting From: Hacker To: Raffaele Subject: Free gift Click here to win • Normale navigazione • Email con link contenente un attacco XSS • Il link effetua una GET sul sito della banca con la QueryString • La banca (non protetta da XSS) restituisce nella pagina html lo script inviato • Lo script viene eseguito dal browser e le informazioni riservate arrivano al pirata
Contromisura di asp.net 1.1<%@ Page validateRequest="true" %>(true by default) • Riconosce un eventuale input malizioso dell'utente e lancia l'eccezione HttpRequestValidationException Se però voglio accettare una stringa html/script dall'utente? • Opzione 1: validateRequest = false (vale per tutta la pagina) e validarla. • Opzione 2: criptare sul client, decrittarla sul server e validarla. • Sul client (durante la onsubmit) si cripta il contenuto con encode di javascript • il contenuto criptato si mette dentro un <input type=hidden> • sul server si usa HttpUtility.UrlDecode per decodificare la stringa La validazione ... • si può usare Server.HtmlEncode per farlo apparire sulla pagina • si può fare il parsing per eliminare i tag pericolosi
<Input type=hidden /> • Spesso viene usato un campo hidden per conservare i dati tra un postback e l'altro • La modifica (tampering) dei campi hidden è banale e, se non controllata adeguatamente, può comportare un duro attacco. Soluzione: • Criptarli prima di mandarli al client • Decrittarli dentro un try/catch quando tornano al server
Protezione del Viewstate • Il Viewstate di default è un campo <input type=hidden /> • Il Viewstate contiene lo stato dei controlli sul lato server • Se non è criptato, è facilmente visibile:http://www.pluralsight.com/toolcontent/ViewStateDecoder11.zip Soluzioni: • Criptarlo: <%@ Page enableViewStateMac=“true” />Mac = machine authentication check • La chiave e il metodo di encryption sono specificati nel tag <machineKey> del machine.config (autogenerazione) • Per crearne e specificarne di nuovi nel web.config: Q312906 • Salvarlo sul server:http://www.aspalliance.com/articleViewer.aspx?aId=72&vId=&pId=http://msdn.microsoft.com/msdnmag/issues/03/02/CuttingEdge/default.aspx
Proteggere le risorse • Molti file non devono poter essere scaricati via http dall'utente • Nel machine.config Asp.net protegge di default alcuni tipi di file dal download (.cs, .config, ...) • Soluzione 1: custodirlo fuori dalla cartella virtuale • Soluzione 2: proteggere il file via NTFS (se si usa impersonation.) • Soluzione 3: proteggere con asp.net • Associare i file da proteggere in IIS all'Isapi di Asp.net • Proteggere (ad esempio) i file mdb nel web.config:<httpHandlers> <add verb="*" path="*.mdb" type="System.Web.HttpForbiddenHandler" /></httpHandlers>
Mappare una estensione in IIS • Affinchè asp.net (e quindi handlers e moduli) abbiano il controllo di un tipo di file (.jpg nell'esempio) è necessario configurare IIS Path dell'isapi di asp.net (copiarla da quella di .aspx)
Q & A ....