La sicurezza di ASP.NET e IIS
Raffaele Rialdi
Microsoft C# MVP
MVP Profile
Blog
[email protected]
Vevy Europe SpA
http://mvp.support.microsoft.com
http://snipurl.com/f0cv
http://blogs/ugidotnet.org/raffaele
Agenda
Spoofing / Tampering
Spying
Sql/script Injection
D.O.S.
Autenticazione
("chi sei?")
•
•
•
•
Anonymous
Basic
Windows
Certificate
•
•
•
•
None
Windows
Forms
Passport
Autorizzazione
("cosa posso fare?")
IIS
• NTFS Access Control List
(ACL)
Asp.net
.aspx, .asmx, .asax, .ascx, .soap, .rem, ...
Web Application
NTFS
LDAP
• UrlAuthorizationModule
• FileAuthorizationModule
• Imperative
• Declarative
SQL
Meccanismi di
Autenticazione


IIS

IIS mappa l'utente su IUSR_nomemacchina
Asp.net lo vede come ""
Utente non viene riconosciuto anche se è in
Lan
Usano lo store delle credenziali di Windows
Richiedono una CAL per ogni utente

La password non viaggia sulla rete

Credenziali in chiaro (necessita SSL)


Anonima

Basic

Digest

Certificate

Windows
Asp.net

Passport

Forms



Differenze architetturali
tra IIS5 e IIS6
IIS 5
aspnet (default)
Configurabile nel
machine.config
IIS 6
Network_service
(default)
User1
App Pool 1
App Pool 2
User2
App Pool 3
appdomain
appdomain
appdomain
appdomain
appdomain
appdomain
appdomain
appdomain
worker
process
(aspnet_wp)
worker
process
(w3wp)
worker
process
(w3wp)
worker
process
(w3wp)
inetinfo (IIS)
account: localsystem
inetinfo (IIS)
account: localsystem
HTTP.SYS (Kernel Mode)
Un account per App Pool.
(token di processo)
Devono essere membri del
gruppo IIS_WPG
Configurabile da IIS
appdomain
Una web
application
per appdomain
Windows Authentication
step-by-step
1.
Web.config di default è pronto:
<authentication mode="Windows" />
2.
Impostare le autorizzazioni
<authorization>
<deny users="?" />
<allow users="*" />
</authorization>
3.
?  utente anonimo
*  tutti gli utenti
Disabilitare l'autenticazione anonima in IIS ...
(prossime slide)
4.
L'utente autenticato è:
(stringa vuota se anonimo)
HttpContext.Current.User.Identity.Name
5.
L'utente usato dal worker process è:
System.Security.Principal.WindowsIdentity.GetCurrent().Name
Internet Information Server
IIS5 (Windows 2000 / XP Pro)
Internet Information Server
IIS6 (Windows 2003)
IIS6 Application pool
Impersonation
(solo con Windows Authentication)

Il token di security dell'utente autenticato viene
impostato sul thread.
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à diverse
Soluzione: impersonation di un utente specifico
<identity impersonate=true user="xxx"
password="zzz" />
I problemi architetturali
di 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 tecnologici
di 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
Scenario tipico di una webapp
worker process
token di processo = aspnet
token di thread (solo se usa impersonation)
Browser
Firewall
Alice
Web Server
Data Server
aspnet
Anche abilitando impersonation
il Data Server verrà accesso come aspnet
Forms Authentication
step-by-step
1.
2.
Abilitare l'autenticazione anonima in IIS
Impostare l'autenticazione e i suoi parametri
<authentication mode="Forms">
<forms name="myCookieName" loginUrl="~/Login.aspx" />
</authentication>
3.
Impostare le autorizzazioni
<authorization>
<deny users="?" />
<allow users="*" />
</authorization>
4.
?  utente anonimo
*  tutti gli utenti
Creare la pagina di login controllare l'utente e autorizzarlo
if(UserDB.Check(txtUsername.Text, txtPassword.Text))
{
FormsAuthentication.RedirectFromLoginPage(
txtUsername.Text, ckRemember.Checked);
}
Forms Authentication
gestire i ruoli
1.
Gestire l'evento Application_AuthenticateRequest
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
UserDB.AssignRoles();
}
2.
Impostare le autorizzazioni per singole parti del sito
<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 Authentication
Gestione 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 Identity
La sicurezza basata sui ruoli secondo il
framework

IIdentity rappresenta l'identità di un utente
WindowsIdentity, FormsIdentity, PassportIdentity, GenericIdentity

AuthenticationType

String. "Windows", "Forms", "Passport", ...
IsAuthenticated

Bool. Indica se l'utente è autenticato
Name

String. Nome dell'utente
IPrincipal contiene l'Identity e i ruoli
WindowsPrincipal, GenericPrincipal
Identity

IIdentity.
IsInRole

Bool. Indica se l'utente appartiene ad un certo ruolo (gruppo)
Forms Authentication
Gestione 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>
Esempio Forms Authentication
Forms Authentication Tip

Diciamo di avere due Web Application ...

Prendiamo in considerazione:
1.
Nome del cookie della Forms authentication
2.
Path del cookie
3.
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 mista
Windows / 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 mista
Windows / 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>
Esempio autenticazione mista
Forms Authentication
con 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
IIS
Basic, Win, ...
Autorizzazione
IIS
NTFS
Controllo
Imperativo
Controllo
dichiarativo
Asp.net
Passport, Form
Asp.net
<authorization ... />
Asp.net
PrincipalPermission, etc.
Raffaele
Pagina
si/no
Codice
si/no
Sicurezza
imperativa e dichiarativa

Gli attrezzi del mestiere:

 Imperativa (bool)
IPrincipal.IsInRole()
if(User.IsInRole("Admins")) { ... }

PrincipalPermission.Demand()
 Imperativa (SecurityException)
PrincipalPermission perm = new PrincipalPermission(null, "Admins");
perm.Demand();

PrincipalPermissionAttribute  Dichiarativa (SecurityException)
PrincipalPermissionAttribute
[PrincipalPermission(SecurityAction.Demand, Role="Admins")]
public void MyAdminMethod() {...}
Esempio SecureHandler
Role Based Authorization
Mai dare informazioni preziose
default: <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)
1.
Web.Config:
<customErrors mode="On" defaultRedirect="~/HttpErrors.aspx" />
....
<httpModules>
<add type="CustomErrorHandler.RafErrorModule,
CustomErrorHandler" name="RafErrorModule"/>
</httpModules>
2.
Due pagine di gestione errore:
SoftError.aspx (per utenti) e HardError.aspx (per admin)
3.
Il Module redirige gli errori a seconda del ruolo dell'utente
4.
Il Module gestisce gli errori Http e le Exception
... vediamo il codice ...
Esempio CustomErrorHandler
HttpRequestValidationException
<%@ 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.
1.
2.
3.
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:
1.
Criptarlo: <%@ Page enableViewStateMac=“true” />
Mac = machine authentication check


2.
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>
<addverb="*" path="*.mdb"
type="System.Web.HttpForbiddenHandler" />
</httpHandlers>
CAS e ASP.net
Livello di Trust
Full
Restrizioni della CAS
• Nessuna restrizione sulle permission.
• Applicazioni possono accedere a risorse controllate dalle impostazioni
del sistema operativo
• Possono essere fatte operazioni che richiedono un alto privilegio
High
• Non si può chiamare codice nativo
• Non si possono usare serviced components
• Non si può scrivere nell'event log
• Non si può accedere alle code di msmq
• Non si può usare data source di tipo OLE DB
Medium
• L'accesso ai file è ristretto alla cartella dell'applicazione
Low
• Non si può accedere a SQL Server
Minimal
• Si ha solo il diritto di esecuzione e nulla di più
• Non si può accedere al registry
• Non si può chiamare CodeAccessPermission.Assert
Q&A
....
© 2003-2004 Microsoft Corporation. All rights reserved.
This presentation is for informational purposes only. Microsoft makes no warranties, express or implied, in this summary.
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 ' '
Prima query
;
drop authors
-- '
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




1. Normale navigazione
2. Email con link contenente un attacco XSS
3. Il link effetua una GET sul sito della banca con la
QueryString
4. La banca (non protetta da XSS) restituisce nella pagina
html lo script inviato
5. Lo script viene eseguito dal browser e le informazioni
riservate arrivano al pirata
Mappare una estensione in IIS
slide post-sessione

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)
Promemoria
slide post-sessione



Installate XP SP2 e Win2K3 SP1!
Aggiornare sempre con Windows Update
Proteggere i dati sensibili




DPAPI per criptare (vedi Pattern & Practices sul sito MSDN)
ASPnet_setreg.exe per salvare credenziali criptate nel registry
(per esempio di sql). Vedi Q329290 per i dettagli.
Eseguire logging e auditing
Usare UrlScan.  UrlScan Monitor (Lorenzo Barbieri)
http://www.gotdotnet.com/Community/Workspaces/workspace.aspx?id=c859a
9fd-3cfd-4d2d-bbe9-4bcc334ed2c3


IIS LockDown (solo IIS5)
Secure Configuration Wizard (solo IIS6  W2K3 SP1)
Scarica

La sicurezza di ASP.NET e IIS