La protezione dall'accesso di codice è un modello di limitazione delle risorse progettato per restringere i tipi di risorse di sistema accessibili dal codice e i tipi di operazioni con privilegi che il codice può eseguire. Queste limitazioni sono indipendenti dall'utente che chiama il codice o dall'account utente con cui il codice è in esecuzione. All'inizio del modulo è riportata una descrizione dettagliata del funzionamento della protezione dall'accesso di codice, seguita da una completa serie di esempi riguardanti tutte le risorse che possono effettuare l'asserzione, richiedere o consentire autorizzazioni di protezione dall'accesso di codice.
Nel modulo viene spiegato dettagliatamente il funzionamento interno della protezione dall'accesso di codice, inclusi valutazione e livello dei criteri, APTCA (AllowPartiallyTrustedCallersAttribute), codice con privilegi, richiesta di autorizzazione, autorizzazione del codice, richieste in fase di linking e asserzioni.
Nel modulo vengono descritti i tre principali vantaggi derivanti dalla protezione dall'accesso di codice e vengono illustrate le modalità di utilizzo di questo tipo di protezione per:
| • | Limitare le azioni del codice
|
| • | Limitare il codice autorizzato a chiamare il codice sviluppato
|
| • | Identificare il codice
|
Il modulo consente di:
| • | Sapere come funziona la protezione dall'accesso di codice e in che cosa consiste il codice con privilegi. |
| • | Utilizzare la protezione dall'accesso di codice per limitare il codice avente la necessità di eseguire l'I/O di file, accedere a dati o al registro eventi, Registro di sistema, servizi directory, variabili di ambiente, servizi Web, socket e DNS. |
| • | Applicare APTCA in maniera protetta e con efficacia. |
| • | Richiedere autorizzazioni e autorizzare il codice. |
| • | Eseguire codice con privilegi nel sandbox. |
| • | Sapere quando utilizzare e quando non utilizzare richieste in fase di linking. |
| • | Sapere quando effettuare e quando non effettuare asserzioni per le richieste di autorizzazione. |
| • | Utilizzare con efficacia le richieste di autorizzazione. |
| • | Utilizzare la protezione dall'accesso di codice per migliorare la protezione quando viene chiamato codice non gestito, utilizzando la serializzazione e i delegati. |
Le informazioni contenute in questo modulo sono valide per i seguenti prodotti e tecnologie:
| • | Microsoft Windows 2000 Server e Microsoft Windows 2003 Server |
| • | Microsoft .NET Framework 1.1 |
| • | ASP.NET 1.1 |
Gli argomenti di questo modulo riprendono quelli del modulo 7 "Creazione di assembly protetti". Viene spiegato come utilizzare la protezione dall'accesso di codice per migliorare ulteriormente la protezione del codice gestito. Per trarre il massimo vantaggio dal modulo:
| • | Leggere il modulo 6 "Informazioni generali sulla protezione di .NET", per una panoramica e un confronto fra la protezione basata sui ruoli o l'utente e la protezione dall'accesso di codice. Nel modulo 6 sono contenute informazioni di base per il modulo corrente. |
| • | Leggere il modulo 7 "Creazione di assembly protetti". Leggere il modulo 7 prima di passare a questo. |
| • | Leggere il modulo 9 "Utilizzo della protezione dall'accesso di codice con ASP.NET". Dopo avere letto il modulo corrente, leggere il modulo 9 se si è specificamente interessati ai criteri di protezione dall'accesso di codice e ai livelli di attendibilità in ASP.NET. |
Per utilizzare in maniera efficace la protezione dall'accesso di codice è necessario conoscere le nozioni fondamentali, quali la terminologia e le modalità di valutazione dei criteri. Per ulteriori informazioni di carattere generale relative alla protezione dall'accesso di codice, vedere la sezione "Risorse aggiuntive" alla fine di questo modulo. Se si conosce già la protezione dall'accesso di codice, è possibile saltare questa sezione e passare direttamente alla sezione "APTCA" (AllowPartiallyTrustedCallersAttribute), riportata più avanti in questo modulo.
La protezione dall'accesso di codice è costituita dai seguenti elementi:
| • | Codice |
| • | Evidenza |
| • | Autorizzazioni |
| • | Criteri |
| • | Gruppi di codice |
Tutto il codice gestito è soggetto alla protezione dall'accesso di codice. Quando viene caricato un assembly, all'assembly viene concesso un set di autorizzazioni all'accesso di codice che determina il tipo di risorse alle quali l'assembly può accedere e quali tipi di operazioni con privilegi può eseguire. Il sistema di protezione di Microsoft .NET Framework utilizza le prove per autenticare (identificare) il codice al fine di concedere autorizzazioni.
Nota: l'assembly è considerato come l'unità ai fini della configurazione e dell'attendibilità per la protezione dall'accesso di codice. Tutto il codice che fa parte dello stesso assembly riceve le stesse autorizzazioni ed ha pertanto la stessa attendibilità.
Le prove vengono utilizzate dal sistema di protezione di .NET Framework per identificare gli assembly. I criteri di protezione dall'accesso di codice utilizzano le prove come supporto per concedere le autorizzazioni corrette all'assembly corretto. Fra le prove correlate al percorso figurano:
| • | URL. L'URL dal quale è stato ottenuto l'assembly. Si tratta dell'URL base di codici nella sua forma non elaborata, ad esempio, http://webserver/dirv/bin/assembly.dll o file://C:/directory1/directory2/assembly.dll. |
| • | Sito. Il sito dal quale è stato ottenuto l'assembly, ad esempio, http://webserver. Il sito deriva dall'URL base di codici. |
| • | Directory dell'applicazione. La directory di base per l'applicazione in esecuzione. |
| • | Zona. La zona dalla quale è stato ottenuto l'assembly, ad esempio, LocalIntranet o Internet. Anche la zona deriva dall'URL base di codici. |
Fra le prove correlate all'autore figurano:
| • | Nome sicuro. Si applica agli assembly con nome sicuro. I nomi sicuri costituiscono un metodo per attribuire una firma digitale a un assembly utilizzando una chiave privata. |
| • | Autore. La firma Authenticode, basata sul certificato X.509, utilizzato per la firma del codice, che rappresenta l'organizzazione di sviluppo. Importante: La prova dell'autore, ossia la firma Authenticode, viene ignorata dall'host ASP.NET, pertanto non può essere utilizzata per configurare i criteri di protezione dall'accesso di codice per le applicazioni Web del lato server. Questa prova viene utilizzata principalmente dall'host di Internet Explorer. |
| • | Hash. L'hash è basato sul contenuto globale dell'assembly e consente di rilevare una compilazione particolare di un brano di codice, indipendentemente dal numero di versione. È utile per rilevare quando gli assembly di terze parti vengono modificati (senza un numero di versione aggiornato) e il loro utilizzo non è stato verificato e autorizzato per la build in questione. |
Le autorizzazioni rappresentano i diritti di cui il codice dispone per accedere a una risorsa protetta o eseguire un'operazione con privilegi. In .NET Framework sono disponibili le autorizzazioni all'accesso di codice e le autorizzazioni di identità del codice. Nelle autorizzazioni all'accesso di codice è incapsulata la capacità di accedere a una determinata risorsa o eseguire un'operazione con privilegi. Le autorizzazioni di identità del codice vengono utilizzate per limitare l'accesso di codice, in base a un aspetto dell'identità del codice chiamante, ad esempio il nome sicuro.
Le autorizzazioni vengono concesse al codice mediante i criteri di protezione dall'accesso di codice, configurati dall'amministratore. Un assembly può influire, utilizzando le richieste di autorizzazione, anche sul set di autorizzazioni ottenute in ultima analisi. I criteri di protezione dall'accesso di codice e le richieste di autorizzazione determinano congiuntamente le operazioni che il codice può eseguire, ad esempio, per accedere al file system, il codice deve disporre di FileIOPermission e, per accedere al Registro di sistema, di RegistryPermission. Per ulteriori informazioni sulle richieste di autorizzazione, vedere la sezione "Richiesta di autorizzazioni", riportata più avanti in questo modulo.
Nota: si utilizzano i set per raggruppare le autorizzazioni in modo da facilitarne l'amministrazione.
Le autorizzazioni possono essere limitate o illimitate. L'autorizzazione FileIOPermission , ad esempio, se illimitata, consente al codice di leggere o scrivere in qualsiasi parte del file system mentre, se limitata, può consentire al codice di leggere i file esclusivamente da una directory specifica.
Se per accedere a una risorsa o eseguire un'altra operazione con privilegi si utilizza una classe della libreria di classi di .NET Framework, la classe invia una richiesta di autorizzazione per assicurare che il codice sviluppato, e qualsiasi altro codice che chiama il codice sviluppato, sia autorizzato ad accedere alla risorsa. La richiesta di autorizzazione fa sì che il runtime ripercorra a ritroso lo stack di chiamate (stack frame per stack frame), esaminando le autorizzazioni di tutti i chiamanti compresi nello stack. Se vengono individuati chiamanti che non dispongono delle autorizzazioni richieste, viene generata un'eccezione SecurityException .
Nel caso di una richiesta in fase di linking non viene eseguito un controllo completo dello stack, ma solo del chiamante immediato, procedendo a ritroso di uno stack frame nello stack di chiamate. Ne consegue che i rischi di protezione correlati all'utilizzo di richieste in fase di linking sono più elevati. È necessario prestare particolare attenzione agli attacchi di tipo luring.
Nota: con un attacco di tipo luring, il codice nocivo accede alle risorse e operazioni esposte dall'assembly, chiamando il codice attraverso un assembly intermediario attendibile.
Per ulteriori informazioni relative al corretto utilizzo delle richieste in fase di linking, vedere la sezione "Richieste in fase di linking" riportata più avanti in questo modulo.
Le classi per l'autorizzazione all'accesso di codice supportano i metodi Assert, Deny e PermitOnly. È possibile utilizzare questi metodi per modificare il funzionamento del controllo dello stack di una richiesta di autorizzazione. Vengono definiti modificatori del controllo dello stack.
Una chiamata al metodo Assert fa sì che il controllo dello stack alla ricerca di un'autorizzazione corrispondente si interrompa alla chiamata ad Assert. Spesso questo metodo viene utilizzato per eseguire il codice con privilegi nel sandbox. Per ulteriori informazioni, vedere la sezione "Assert e RevertAssert", riportata più avanti in questo modulo.
Una chiamata al metodo Deny causa il mancato controllo dello stack dal punto in cui viene raggiunta un'autorizzazione corrispondente in poi. Se si chiama codice non attendibile, è possibile utilizzare il metodo Deny per limitare le potenzialità del codice chiamato.
Una chiamata al metodo PermitOnly causa il mancato controllo di uno stack senza corrispondenze. Come avviene per il metodo Deny , si tende a non utilizzarlo spesso, ma può essere impiegato per limitare le azioni di codice non attendibile che potrebbe essere chiamato.
I criteri di protezione dall'accesso di codice vengono configurati dagli amministratori e determinano le autorizzazioni concesse agli assembly. È possibile stabilire criteri a quattro livelli:
| • | Organizzazione. Per applicare criteri al livello dell'organizzazione. |
| • | Computer. Per applicare criteri al livello del computer. |
| • | Utente. Per applicare criteri al livello dell'utente. |
| • | Dominio applicazione. Per configurare il dominio applicazione in cui viene caricato un assembly. In ASP.NET si implementano i criteri del dominio applicazione per consentire la configurazione dei criteri di protezione dall'accesso di codice per le applicazioni e i servizi Web. Per ulteriori informazioni sui criteri del dominio applicazione di ASP.NET, leggere il modulo 9 "Utilizzo della protezione dall'accesso di codice con ASP.NET". |
Le impostazioni dei criteri vengono mantenute nei file di configurazione XML. I primi tre livelli di criteri (organizzazione, computer e utente) possono essere configurati mediante lo strumento di configurazione di .NET Framework, contenuto nel gruppo di programmi Strumenti di amministrazione, o l'utilità da riga di comando Caspol.exe. I criteri a livello del dominio applicazione di ASP.NET devono attualmente essere modificati con un editor di testo o XML.
Per ulteriori informazioni sui file dei criteri e i relativi percorsi, vedere il modulo 19 "Protezione dell'applicazione ASP.NET e dei servizi Web".
Ogni file dei criteri contiene un insieme gerarchico di gruppi di codice. I gruppi di codice vengono utilizzati per assegnare le autorizzazioni agli assembly. Un gruppo di codice è costituito da due elementi:
| • | Una condizione di appartenenza . È basata su prove, ad esempio la zona o il nome sicuro di un assembly. |
| • | Un set di autorizzazioni. Le autorizzazioni contenute nel set vengono concesse agli assembly la cui prova soddisfa la condizione di appartenenza. |
Nella figura 8.1 è illustrata una panoramica semplificata della protezione dall'accesso di codice.

Figura 8.1
Vista semplificata della protezione dall'accesso di codice
Di seguito è riportato un riepilogo dei passaggi illustrati nella figura 8.1.
1. | Viene caricato un assembly. Questa operazione viene eseguita da un host di dominio applicazione. In un server Web che carica un assembly di applicazione Web si tratta dell'host ASP.NET. |
2. | La prova viene raccolta dall'assembly e presentata dall'host. |
3. | La prova viene valutata a fronte dei criteri di protezione definiti. |
4. | L'output della valutazione dei criteri di protezione è costituito da uno o più set di autorizzazioni denominati che definiscono le autorizzazioni concesse all'assembly. Nota: un assembly può includere richieste di autorizzazione, che possono ridurre ulteriormente le autorizzazioni concesse. |
5. | Il codice contenuto nell'assembly richiede autorizzazioni corrette per accedere a una risorsa limitata o eseguire un'operazione con privilegi. Tutte le classi di base di .NET Framework che accedono a risorse o eseguono operazioni con privilegi contengono le richieste di autorizzazione corrette. La classe FileStream , ad esempio, richiede l'autorizzazioneFileIOPermission, la classe Registry richiede l'autorizzazione RegistryPermission, e così via. |
6. | Se all'assembly e relativi chiamanti sono state concesse le autorizzazioni richieste, l'operazione può procedere. In caso contrario, verrà generata un'eccezione di protezione. |
Quando la prova viene elaborata attraverso il motore dei criteri, l'output è costituito da un set di autorizzazioni che definisce le autorizzazioni concesse a un assembly. La concessione dei criteri viene calcolata a ogni livello della gerarchia dei criteri: organizzazione, computer, utente e dominio applicazione. I criteri concessi a ogni livello vengono quindi uniti mediante un'operazione di intersezione per ottenere i criteri infine concessi. Si utilizza un'intersezione per assicurare che i criteri di livello inferiore nella gerarchia non possano aggiungere autorizzazioni non concesse a livelli superiori. Ciò impedisce la concessione da parte di un singolo utente o dominio applicazione di ulteriori autorizzazioni non concesse dall'amministratore dell'organizzazione.
Nella figura 8.2 è illustrato il funzionamento dell'operazione di intersezione, che assicura che la concessione di autorizzazioni risultante sia determinata da tutti i livelli di criteri della gerarchia.

Figura 8.2
Intersezione dei criteri fra tutti i livelli
Dalla figura 8.2 si evince che l'operazione di intersezione assicura che solo le autorizzazioni concesse a tutti i livelli vadano a fare parte delle autorizzazioni infine concesse.
È possibile aggiungere all'assembly attributi di protezione per specificarne i requisiti di autorizzazione. È possibile specificare che all'assembly debba essere concesso il set minimo di autorizzazioni perché possa essere eseguito, ma ciò non influisce sulle autorizzazioni effettivamente concesse. È altresì possibile specificare le autorizzazioni facoltative, non strettamente necessarie, che possono essere utilizzate dall'assembly e quali autorizzazioni si desidera rifiutare. Le autorizzazioni rifiutate sono quelle da non concedere mai all'assembly, neanche se consentite dai criteri di protezione.
Se si richiedono autorizzazioni facoltative, la combinazione di autorizzazioni facoltative e minime diviene oggetto di un'operazione di intersezione con le autorizzazioni concesse dai criteri, che va ulteriormente a ridurle. Le autorizzazioni specificamente rifiutate vengono rimosse nei criteri. Questi concetti sono riepilogati dalla formula riportata di seguito, dove AC corrisponde ai criteri concessi dall'amministratore, definiti criteri di protezione e Amin, Afac e Arifiutate sono le richieste di autorizzazione aggiunte all'assembly dallo sviluppatore.
Autorizzazioni concesse risultanti = (AC ∩ (Amin U Afac)) - Arifiutate
Per ulteriori informazioni relative all'utilizzo delle richieste di autorizzazione, le loro implicazioni e quando utilizzarle, vedere la sezione "Richiesta di autorizzazioni", riportata più avanti in questo modulo.
Ogni singolo file dei criteri a ogni livello specifico consiste in una disposizione gerarchica di gruppi di codice. Questi gruppi di codice includono le condizioni di appartenenza utilizzate per determinare a quali assembly si applicano e quali set di autorizzazioni vengono utilizzati per determinare le autorizzazioni che devono essere concesse agli assembly corrispondenti. La struttura gerarchica consente di assegnare a un assembly vari set di autorizzazioni e permette ai criteri di protezione di supportare la logica AND e OR semplice. Si considerino ad esempio i criteri di protezione illustrati nella figura 8.3.

Figura 8.3
Gruppi di codice gerarchici a un singolo livello di criteri
Nota: il gruppo di codice Codice tutti è un gruppo di codice speciale che corrisponde a tutti gli assembly. Costituisce il livello principale dei criteri di protezione e in sé non concede autorizzazioni, in quanto è associato al set di autorizzazioni chiamato Nulla.
Si considerino le autorizzazioni concesse in base ai criteri di protezione illustrati nella figura 8.3.
| • | A tutti gli assembly che traggono origine da Zona_Computer_Locale (assembly installati a livello locale) vengono concesse le autorizzazioni definite dal set FullTrust. Si tratta di un set di autorizzazioni predefinito all'installazione di .NET Framework e rappresenta il set illimitato di tutte le autorizzazioni. |
| • | Agli assembly il cui autore è Società1 e che traggono origine dalla zona intranet vengono concesse le autorizzazioni definite dal set di autorizzazioni predefinito Zona_IntranetLocale e dal set di autorizzazioni SetASoc1 personalizzato. |
| • | Agli assembly il cui autore è Società2 vengono concesse le autorizzazioni definite dal set di autorizzazioni SetASoc2 personalizzato. |
| • | Agli assembly scaricati da a.b.c.com vengono concesse le autorizzazioni definite dal set di autorizzazioni SetAABC personalizzato. |
Nota: se non viene soddisfatta la condizione di appartenenza di un determinato gruppo di codice non viene valutato alcun gruppo figlio.
L'elaborazione e l'attraversamento della gerarchia di criteri possono essere ottimizzati utilizzando due attributi specificati a livello del gruppo di codice, entrambi impostabili mediante lo strumento di configurazione di .NET Framework. Sono:
| • | Esclusivo |
| • | Livello finale Nota: i criteri a livello di dominio applicazione, ad esempio i criteri ASP.NET per le applicazioni Web del lato server, vengono sempre valutati, a prescindere dall'impostazione del livello finale. |
Un assembly che dispone di un nome sicuro non può essere chiamato da un assembly parzialmente attendibile, ossia non totalmente attendibile, a meno che l'assembly con il nome sicuro non contenga l'attributo AllowPartiallyTrustedCallersAttribute (APTCA) come indicato di seguito:
[assembly: AllowPartiallyTrustedCallersAttribute()]
Si tratta di una strategia per diminuire i rischi, volta ad assicurare che il codice sviluppato non possa essere inavvertitamente esposto a codice con attendibilità parziale e quindi potenzialmente nocivo. Ai tipi contenuti in un assembly con nome sicuro Common Language Runtime aggiunge, senza avvisare, una richiesta in fase di linking per il set di autorizzazioni FullTrust in tutti i membri pubblicamente accessibili. Includendo l'attributo APTCA si inibisce la richiesta in fase di linking.
Se si utilizza l'attributo APTCA il codice è più sensibile agli attacchi e ne consegue che è particolarmente importante riesaminarlo per verificare che sia privo di vulnerabilità di protezione. Utilizzare l'attributo APTCA solo se strettamente necessario.
Nel contesto di un'applicazione Web del lato server, utilizzare l'attributo APTCA solo quando l'assembly deve supportare chiamanti con attendibilità parziale. Questa situazione può verificarsi nelle seguenti circostanze:
| • | L'assembly deve essere chiamato da un'applicazione Web con attendibilità parziale. Si tratta di applicazioni il cui livello <trust> non è impostato come totale. Per ulteriori informazioni sulle applicazioni Web con attendibilità parziale e l'utilizzo dell'attributo APTCA in questa situazione, vedere il modulo 9 "Utilizzo della protezione dall'accesso di codice con ASP.NET". |
| • | L'assembly deve essere chiamato da un altro assembly al quale sono state concesse autorizzazioni limitate dall'amministratore della protezione dall'accesso di codice. |
| • | L'assembly deve essere chiamato da un altro assembly che rifiuta autorizzazioni specifiche utilizzando SecurityAction.RequestRefuse o SecurityAction.RequestOptional. Ciò fa dell'assembly chiamante un assembly con attendibilità parziale. |
| • | L'assembly deve essere chiamato da un altro assembly che utilizza un modificatore del controllo dello stack (ad esempio Deny o PermitOnly) per limitare il codice a valle. |
Se si tenta di chiamare un assembly con nome sicuro non contrassegnato con l'attributo APTCA da codice con attendibilità parziale, quale un'applicazione Web, verrà visualizzata un'eccezione simile a quella illustrata nella Figura 8.4. Si noti che nell'eccezione non sono forniti dettagli relativi alle autorizzazioni, ma è semplicemente indicato che le autorizzazioni richieste (in questo caso FullTrust) non possono essere acquisite dall'assembly chiamante. In questo caso il testo della descrizione poco chiaro significa che l'errore si è verificato perché il livello <trust> dell'applicazione era impostato diversamente da totale.

Figura 8.4
Risultato della chiamata a un assembly dotato di nome sicuro da parte di codice con attendibilità parziale
Per superare questa eccezione è necessario concedere FullTrust al codice chiamante o assegnare l'attributo APTCA all'assembly chiamato. Si noti che per i singoli tipi che fanno parte di un assembly con attributo APTCA potrebbero comunque essere richiesti chiamanti con attendibilità totale, in quanto nei tipi potrebbe essere inclusa una richiesta in fase di linking implicita o una normale richiesta di attendibilità totale, come illustrato negli esempi riportati di seguito.
[PermissionSet(SecurityAction.LinkDemand, Name="FullTrust")] [PermissionSet(SecurityAction.Demand, Unrestricted=true)]
Quando si progettano e si costruiscono assembly, è necessario essere in grado di identificare il codice con privilegi. Questo ha implicazioni notevoli per la protezione dall'accesso di codice. Il codice con privilegi è codice gestito che accede a risorse protette o esegue altre operazioni delicate per la protezione, ad esempio chiamare codice non gestito o utilizzare la serializzazione o la reflection. Il codice con privilegi dispone di questi privilegi in quanto la protezione dall'accesso di codice deve concedergli autorizzazioni specifiche perché possa funzionare.
Le risorse con privilegi per le quali il codice richiede autorizzazioni specifiche di protezione dall'accesso di codice sono indicate nella Tabella 8.1.
Tabella 8.1 Risorse protette e autorizzazioni associate
| Risorsa protetta | Autorizzazione necessaria |
Accesso ai dati | SqlClientPermission |
Servizi directory | DirectoryServicesPermission |
Database DNS | DnsPermission |
Registro eventi | EventLogPermission |
Variabili di ambiente | EnvironmentPermission |
File system | FileIOPermission |
Archiviazione isolata | IsolatedStoragePermission |
Code di messaggi | MessageQueuePermission |
Contatori prestazioni | PerformanceCounterPermission |
Stampanti | PrinterPermission |
Registro di sistema | RegistryPermission |
Socket | SocketPermission |
Servizi Web (e altre risorse Internet HTTP) | WebPermission |
Le operazioni con privilegi sono riportate nella Tabella 8.2, unitamente alle autorizzazioni associate richieste dal codice chiamante.
Tabella 8.2 Operazioni con privilegi e autorizzazioni associate
| Operazione | Autorizzazione necessaria |
Creazione e controllo dei domini applicazioni | SecurityPermission con |
Specificazione dei domini applicazioni dei criteri | SecurityPermission con |
Asserzione delle autorizzazioni di protezione | SecurityPermission con |
Creazione e gestione delle prove | SecurityPermission con |
Creazione e gestione degli oggetti identità | SecurityPermission con |
Configurazione dei tipi e servizi remoti dei canali | SecurityPermission con |
Gestione dei criteri di protezione | SecurityPermission con |
Serializzazione | SecurityPermission con |
Operazioni di threading | SecurityPermission con |
Reflection | ReflectionPermission |
Chiamate a codice non gestito | SecurityPermission con |
Quando si progettano e si sviluppano assembly, creare un elenco di tutte le risorse alle quali il codice accede e di tutte le operazioni con privilegi eseguite dal codice. Al momento della distribuzione, queste informazioni potranno essere utili all'amministratore per configurare adeguatamente i criteri di protezione dall'accesso di codice e per diagnosticare problemi correlati alla protezione.
Il modo migliore per comunicare i requisiti di autorizzazione del codice consiste nell'utilizzare attributi di protezione dichiarativi a livello di assembly per specificare i requisiti minimi. Di norma questi vengono inseriti in Assemblyinfo.cs o Assemblyinfo.vb. Ciò consente all'amministratore o utente dell'assembly di controllare quali autorizzazioni l'assembly richiede utilizzando lo strumento Permview.exe.
È possibile utilizzare il metodo SecurityAction.RequestMinimum unitamente ad attributi di autorizzazione dichiarativi per specificare il set minimo di autorizzazioni necessario per l'esecuzione dell'assembly. Se l'assembly necessita, ad esempio, di accedere al Registro di sistema, ma solo per recuperare dati di configurazione da una chiave specifica, utilizzare un attributo simile a quanto riportato di seguito:
[assembly: RegistryPermissionAttribute(
SecurityAction.RequestMinimum,
Read=@"HKEY_LOCAL_MACHINE\SOFTWARE\YourApp")]
Se si è certi a priori che il codice verrà eseguito in ambiente con attendibilità totale e che disporrà del set di autorizzazioni completo e illimitato, utilizzare RequestMinimum è di minore importanza. È tuttavia buona norma specificare i requisiti di autorizzazione dell'assembly.
Nota: gli attributi di autorizzazione accettano un elenco delimitato da virgole di proprietà e valori di proprietà dopo gli argomenti obbligatori del costruttore. Questi vengono utilizzati per inizializzare l'oggetto autorizzazione sottostante. Un modo rapido per individuare i nomi di proprietà supportati consiste nell'utilizzare Ildasm.exe sull'assembly contenente il tipo dell'attributo di autorizzazione.
Se si utilizza il metodo SecurityAction.RequestOptional , all'assembly non verranno concesse altre autorizzazioni se non quelle specificate con SecurityAction.RequestMinimum e SecurityAction.RequestOptional , nonostante avrebbero potuto esserne concesse altre in base ai criteri di protezione.
SecurityAction.RequestRefuse consente di avere la certezza che all'assembly non possano essere concesse autorizzazioni non necessarie da parte dei criteri di protezione dall'accesso di codice. Se l'assembly, ad esempio, non richiama codice non gestito, è possibile utilizzare l'attributo indicato di seguito per assicurare che i criteri di protezione dall'accesso di codice non concedano all'assembly l'autorizzazione al codice non gestito.
[assembly: SecurityPermissionAttribute(SecurityAction.RequestRefuse,
UnmanagedCode=true)]Se si utilizza RequestOptional, viene effettuata un'intersezione fra il set di autorizzazioni specificate con RequestOptional e RequestMinimum , e le autorizzazioni concesse all'assembly in base ai criteri. Vale a dire che tutte le altre autorizzazioni dell'assembly che non rientrano nei set RequestOptional e RequestMinimum vengono rimosse. Se si utilizza RequestRefuse vengono inoltre rimosse le richieste rifiutate.
Se si utilizza RequestOptional o RequestRefuse, l'assembly diviene pertanto un assembly ad attendibilità parziale, il che si ripercuote sulla chiamata ad altri assembly. Nella scelta tra utilizzare SecurityAction.RequestOptional o SecurityAction.RequestRefuse possono essere d'aiuto le seguenti considerazioni:
| • | Non utilizzarli se si ha la necessità di chiamare direttamente un assembly con nome sicuro senza AllowPartiallyTrustedCallersAttribute (APTCA) in quanto il loro utilizzo ne impedisce la chiamata. Molti assembly di .NET Framework con nome sicuro contengono tipi che non supportano chiamanti con attendibilità parziale e non includono l'attributo APTCA. Per ulteriori informazioni e un elenco degli assembly che supportano chiamanti con attendibilità parziale, vedere "Sviluppo di applicazioni con attendibilità parziale" nel modulo 9 "Utilizzo della protezione dall'accesso di codice con ASP.NET". Se si devono effettuare chiamate ad assembly con nome sicuro senza APTCA, informare gli amministratori che installano il codice sviluppato del fatto che, per funzionare correttamente, a tale codice deve essere concessa l'attendibilità totale mediante i criteri di protezione dall'accesso di codice. |
| • | Se non è necessario accedere ad assembly APTCA, aggiungere richieste di autorizzazione per rifiutare le autorizzazioni notoriamente non necessarie per l'assembly. Eseguire il test del codice in una fase precoce per verificare che tali autorizzazioni non siano realmente necessarie. |
| • | Se il codice a valle necessita delle autorizzazioni rifiutate, un metodo compreso fra il codice sviluppato e quello a valle dovrà effettuare un'asserzione per l'autorizzazione. In caso contrario verrà generata un'eccezione SecurityException quando il controllo dello stack arriverà al codice sviluppato. |
La protezione dall'accesso di codice consente di autorizzare il codice che chiama l'assembly. Viene così ridotto il rischio che codice nocivo possa chiamare il codice sviluppato. È ad esempio possibile utilizzare le autorizzazioni di identità per limitare il codice chiamante in base alla prova dell'identità, ad esempio il componente chiave pubblica del relativo nome sicuro. È altresì possibile utilizzare richieste di autorizzazione all'accesso di codice esplicite per assicurare che il codice che chiama l'assembly disponga delle autorizzazioni necessarie per accedere alla risorsa o eseguire l'operazione con privilegi esposta dall'assembly.
Di solito non si richiedono esplicitamente le autorizzazioni all'accesso di codice. Queste richieste vengono effettuate direttamente dalle classi di .NET Framework e non è necessario duplicarle. Esistono tuttavia occasioni in cui occorre inviare richieste esplicite, ad esempio se il codice sviluppato espone una risorsa personalizzata utilizzando codice non gestito o se accede a dati memorizzati nella cache. Sono disponibili le seguenti modalità di autorizzazione del codice:
| • | Limitare il codice in grado di chiamare il codice sviluppato. |
| • | Limitare l'ereditarietà. |
| • | Prendere in considerazione la protezione dei dati memorizzati nella cache. |
| • | Proteggere le risorse personalizzate con autorizzazioni personalizzate. |
Un metodo contrassegnato come public può essere chiamato da qualsiasi codice esterno all'assembly corrente. Per limitare ulteriormente altro codice in grado di chiamare i metodi utilizzati è possibile ricorrere a una richiesta di autorizzazione dell'identità di protezione dall'accesso di codice, come illustrato nell'esempio riportato di seguito.
public sealed class Utility
{
// Although SomeOperation() is a public method, the following
// permission demand means that it can only be called by assemblies
// with the specified public key.
[StrongNameIdentityPermission(SecurityAction.LinkDemand,
PublicKey="00240000048...97e85d098615")]
public static void SomeOperation() {}
}
Nel codice sopra riportato è presente una richiesta in fase di linking. Ne consegue l'autorizzazione del chiamante immediato. Il codice sviluppato risulterebbe pertanto potenzialmente soggetto agli attacchi di tipo luring, nei quali un assembly nocivo potrebbe accedere a risorse o operazioni protette, fornite dal proprio assembly attraverso un intermediario attendibile avente il nome sicuro specificato.
A seconda della natura e delle funzionalità fornite dalla classe, per il codice chiamante potrebbe essere necessario richiedere un'ulteriore autorizzazione rispetto alla richiesta in fase di linking basata sull'identità. È in alternativa possibile prendere in considerazione di utilizzare una richiesta completa unitamente a StrongNameIdentityPermission, sebbene per questo si presuma che tutto il codice incluso nello stack di chiamate sia firmato con un nome sicuro utilizzando la stessa chiave privata.
Nota: l'invio di una richiesta di controllo dell'intero stack per StrongNameIdentityPermission non funziona se l'assembly viene chiamato da un'applicazione o servizio Web. Questo perché non è possibile attribuire un nome sicuro alle classi compilate dinamicamente associate ad applicazioni o servizi Web ASP.NET.
| • | Per estrarre una chiave pubblica da un assembly
|
| • | Per estrarre la chiave pubblica da un file con una coppia di chiavi
|
Se la classe è progettata come classe base, è possibile limitare il codice che può derivarne utilizzando una richiesta di ereditarietà unitamente a StrongNameIdentityPermission , come illustrato nell'esempio riportato di seguito. Ciò impedisce che assembly che non dispongono della chiave privata corrispondente alla chiave pubblica contenuta nella richiesta ereditino dalla classe.
// The following inheritance demand ensures that only code within the
// assembly with the specified public key (part of the assembly's strong
// name can sub class SomeRestrictedClass
[StrongNameIdentityPermission(SecurityAction.InheritanceDemand,
PublicKey="00240000048...97e85d098615")]
public class SomeRestrictedClass
{
}Se si accede a una risorsa utilizzando una delle classi di .NET Framework, la classe invia una richiesta di autorizzazione corretta per il tipo di risorsa in questione. Se in seguito i dati vengono memorizzati nella cache per ragioni di prestazioni, è opportuno prendere in considerazione di inviare una richiesta di autorizzazione all'accesso di codice esplicita prima di accedere ai dati contenuti nella cache. Ciò assicura che il codice chiamante sia autorizzato ad accedere al tipo di risorsa specifico. Se, ad esempio, i dati vengono prima letti da un file e in seguito memorizzati nella cache, e si desidera assicurare che il codice chiamante sia autorizzato, inviare una richiesta FileIOPermission , come illustrato nell'esempio riportato di seguito.
// The following demand assumes the cached data was originally retrieved from
// C:\SomeDir\SomeFile.dat
new FileIOPermission(FileIOPermissionAccess.Read,
@"C:\SomeDir\SomeFile.dat").Demand();
// Now access the cache and return the data to the callerSe si espone una risorsa o operazione utilizzando codice non gestito, è opportuno eseguire il codice wrapper nel sandbox e prendere in considerazione di richiedere un'autorizzazione personalizzata per autorizzare il codice chiamante.
Ai chiamanti con attendibilità totale l'autorizzazione personalizzata viene concessa automaticamente, purché il tipo di autorizzazione implementi l'interfaccia IUnrestrictedPermission. I chiamanti con attendibilità parziale non disporranno dell'autorizzazione a meno che questa non venga specificamente concessa dai criteri di protezione dall'accesso di codice. Viene così assicurato che il codice non attendibile non possa chiamare l'assembly per accedere alla risorsa personalizzata da questo esposta. Il sandboxing implica inoltre che non si è costretti a concedere la potente autorizzazione UnmanagedCodePermission al codice che deve chiamare il codice sviluppato.
Per ulteriori informazioni sulle chiamate a codice non gestito, vedere la sezione "Codice non gestito", riportata più avanti in questo modulo. Per un esempio di implementazione di un'autorizzazione personalizzata, vedere "Procedura: Creare un'autorizzazione per la crittografia personalizzata" nella sezione "Procedure" di questa guida.
Una richiesta in fase di linking differisce da una normale richiesta di autorizzazione in quanto il runtime richiede autorizzazioni esclusivamente al chiamante immediato e non esegue un controllo completo dello stack. Le richieste in fase di linking vengono effettuate al momento della compilazione JIT e possono essere specificate solo in modo dichiarativo.
Prima di utilizzare una richiesta in fase di linking è necessario fare tutte le considerazioni del caso, in quanto il loro utilizzo può causare vulnerabilità. Se si utilizzano richieste in fase di linking prendere in considerazione i seguenti problemi:
| • | Attacchi di tipo luring |
| • | Prestazioni e richieste in fase di linking |
| • | Metodi chiamanti e richieste in fase di linking |
| • | Utilizzo congiunto di richieste in fase di linking a livello di classe e di metodo |
| • | Interfacce e richieste in fase di linking |
| • | Strutture e richieste in fase di linking |
| • | Metodi virtuali e richieste in fase di linking |
Se si protegge il codice con una richiesta in fase di linking, sarà vulnerabile agli attacchi di tipo luring, nei quali il codice dannoso riesce ad accedere alla risorsa o operazione esposta dal codice sviluppato attraverso un intermediario attendibile, come illustrato nella Figura 8.5.

Figura 8.5
Esempio di attacco di tipo luring con richieste in fase di linking
Nella Figura 8.5 i metodi contenuti nell'assembly X, che accede a una risorsa protetta, sono protetti con una richiesta in fase di linking di una chiave pubblica specifica che utilizza un'autorizzazione StrongNameIdentityPermission). Gli assembly A, B e C sono firmati mediante una chiave privata corrispondente alla chiave pubblica considerata attendibile per l'assembly X, pertanto questi assembly possono chiamare l'assembly X. Gli assembly A, B e C sono soggetti a un attacco di tipo luring se i chiamanti non vengono controllati alla ricerca di una prova specifica prima di effettuare chiamate all'assembly X. L'assembly D, ad esempio, che non è firmato con la stessa chiave privata, non può chiamare direttamente l'assembly X. Potrebbe tuttavia accedere all'assembly X attraverso l'assembly attendibile A, se A non controlla i propri chiamanti attraverso un'altra richiesta in fase di linking o una richiesta completa.
Utilizzare le richieste in fase di linking in un assembly esclusivamente quando i chiamanti dell'assembly non ne espongono ulteriormente le funzionalità, ad esempio se il chiamante è un'applicazione e non una libreria, o quando si è certi che sia sufficiente verificare l'identità del chiamante immediato con una richiesta di autorizzazione dell'identità.
Rispetto ad altri problemi di prestazioni di applicazioni Web, quali la latenza della rete e l'accesso al database, l'impatto del controllo dello stack è contenuto. Non utilizzare le richieste in fase di linking esclusivamente per ottenere un vantaggio a livello di prestazioni. Le richieste complete offrono un livello di protezione molto più elevato.
Se si chiama un metodo protetto di richiesta in fase di linking, per effetto di tale richiesta verrà controllato solo il codice sviluppato. In questa situazione è opportuno accertarsi che tale codice adotti misure adeguate per autorizzare i chiamanti, ad esempio la richiesta di un'autorizzazione.
Le richieste in fase di linking a livello di metodo hanno la precedenza rispetto a quelle a livello di classe. Nel brano di codice riportato di seguito, ad esempio, la richiesta in fase di linking di FileIOPermission deve essere ripetuta nella dichiarazione del metodo, altrimenti la richiesta in fase di linking di EnvironmentPermission sostituirà quella a livello di classe di FileIOPermission.
[FileIOPermission(SecurityAction.LinkDemand, Unrestricted=true)]
public sealed class SomeClass
{
// The unrestricted FileIOPermission link demand must be restated at the
// method level, if the method is decorated with another link demand.
// Failure to do so means that (in this example) that the
// EnvironmentPermission link demand would override the class level
// FileIOPermission link demand
[FileIOPermission(SecurityAction.LinkDemand, Unrestricted=true)]
[EnvironmentPermission(SecurityAction.LinkDemand, Read="PATH")]
public void SomeMethod()
{
}
}Se la classe implementa un'interfaccia e una delle implementazioni dei metodi contiene una richiesta in fase di linking, prestare attenzione affinché nella dichiarazione del metodo contenuta nella definizione dell'interfaccia sia presente la stessa richiesta in fase di linking. In caso contrario, per ignorare la richiesta in fase di linking, il chiamante dovrà semplicemente chiamare il metodo attraverso l'interfaccia. Di seguito è riportato un esempio.
public interface IMyInterface
{
// The link demand shown on the method implementation below
// should be repeated here
void Method1();
}
public class MyImplementation : IMyInterface
{
// The method implementation has a link demand but the interface does not
[SecurityPermission(SecurityAction.LinkDemand,
Flags=SecurityPermissionFlag.ControlPrincipal)]
public void Method1()
{
}
}
Utilizzando il codice riportato di seguito, il chiamante è soggetto alla richiesta in fase di linking:
MyImplementation t = new MyImplementation(); t.Method1();
Utilizzando il codice riportato di seguito, il chiamante non è soggetto alla richiesta in fase di linking:
IMyInterface i = new MyImplementation(); i.Method1();
Le richieste in fase di linking non impediscono la costruzione di strutture da parte di chiamanti non attendibili. Questo avviene perché i costruttori predefiniti non vengono generati automaticamente per le strutture. La richiesta in fase di linking a livello di struttura si applica pertanto solo se si utilizza un costruttore esplicito. Ad esempio:
[SecurityPermission(SecurityAction.LinkDemand,
Flags=SecurityPermissionFlag.ControlPrincipal)]
public struct SomeStruct
{
// This explicit constructor is protected by the link demand
public SomeStruct(int i)
{
field = i;
}
private int field;
}
Le due righe di codice riportate di seguito hanno entrambe come esito una nuova struttura con il campo inizializzato a zero. Solo la prima riga, che utilizza il costruttore esplicito, è tuttavia soggetta a una richiesta in fase di linking.
SomeStruct s = new SomeStruct(0); SomeStruct s = new SomeStruct();
La seconda riga non è soggetta a una richiesta in fase di linking perché non viene generato alcun costruttore predefinito. Se si trattasse di una classe anziché di una struttura, il compilatore genererebbe un costruttore predefinito contenente un'annotazione relativa alla richiesta in fase di linking specificata.
Se si utilizza una richiesta in fase di linking per proteggere l'override di un metodo in una classe derivata, avere cura di inserirla anche nel corrispondente metodo della classe base virtuale. In caso contrario non verrebbe eseguita alcuna richiesta in fase di linking qualora il compilatore JIT individuasse un riferimento al tipo della classe base e non fosse presente una richiesta in fase di linking.
È possibile chiamare il metodo CodeAccessPermission.Assert per evitare che una richiesta si propaghi oltre il frame dello stack corrente. Utilizzando Assert si garantisce l'attendibilità dei chiamanti del codice. Data la possibilità di attacchi di tipo luring, Assert deve essere utilizzato con cautela.
Lo si utilizza più spesso per eseguire il codice con privilegi nel sandbox. Se si sviluppa codice che chiama Assert, è necessario assicurare che siano in atto misure di protezione alternative per l'autorizzazione del codice chiamante. I consigli seguenti contribuiscono a ridurre i rischi al minimo.
| • | Utilizzare lo schema richiesta/asserzione |
| • | Ridurre la durata di Assert |
Richiedere un'autorizzazione specifica prima di chiamare Assert è un modo efficace per autorizzare il codice a monte. A volte può essere possibile richiedere un tipo di autorizzazione predefinito per autorizzare il codice chiamante.
Spesso se l'assembly espone funzionalità non disponibili nella libreria di classi di .NET Framework, ad esempio la chiamata a DPAPI (Data Protection API), è necessario sviluppare un'autorizzazione personalizzata e richiederla per autorizzare i chiamanti. Si potrebbe ad esempio sviluppare l'autorizzazione personalizzata Crittografia per autorizzare i chiamanti a un assembly wrapper DPAPI gestito. Richiedere questa autorizzazione e quindi effettuare l'asserzione dell'autorizzazione del codice non gestito costituisce un modo efficace per autorizzare il codice chiamante.
Per ulteriori informazioni su questo tipo di approccio e lo sviluppo di autorizzazioni personalizzate, vedere "Procedura: creare un'autorizzazione per la crittografia personalizzata" nella sezione "Procedure" di questa guida.
Se è necessario chiamare Assert solo per soddisfare le richieste di un solo metodo a valle chiamato dal codice, inserire Assert immediatamente prima della chiamata al metodo a valle, quindi chiamare immediatamente RevertAssert per mantenere al minimo le dimensioni della finestra di asserzione e per assicurare che il codice seguente chiamato dal metodo non venga inavvertitamente eseguito senza errori perché Assert è ancora valido.
È prassi comune inserire la chiamata a RevertAssert in un blocco finally per assicurare che venga sempre eseguita anche nel caso sia generata un'eccezione.
Limitare e costruire codice con privilegi minimi equivale ad adottare il principio dei privilegi minimi quando si configura un account utente o di servizio. Limitando le autorizzazioni di protezione dall'accesso di codice per il codice che si sviluppa si riducono al minimo le probabilità che possa essere utilizzato in maniera dannosa.
Sono disponibili due modi per limitare il codice in modo da restringere le risorse alle quali può accedere e le altre operazioni con privilegi che può eseguire:
| • | Utilizzo della concessione di autorizzazioni basate su criteri |
| • | Utilizzo di modificatori del controllo dello stack |
È possibile configurare i criteri di protezione dall'accesso di codice per concedere a un determinato assembly un set di autorizzazioni limitato. Se ne contiene così la capacità di accedere alle risorse o eseguire altre operazioni con privilegi. Per ulteriori informazioni, vedere"Procedura: utilizzo dei criteri di protezione dall'accesso di codice per vincolare un assembly" nella sezione "Procedure" di questa guida.
È possibile utilizzare modificatori del controllo dello stack per assicurare che siano disponibili solo autorizzazioni specifiche per il codice chiamato. È ad esempio possibile utilizzare SecurityAction.PermitOnly per assicurare che il metodo sviluppato e gli altri metodi chiamati dispongano esclusivamente di un set di autorizzazioni limitato. Nell'esempio riportato di seguito viene applicato un set di autorizzazioni molto restrittivo. Il codice dispone solo dell'autorizzazione all'esecuzione, non può accedere alle risorse o eseguire altre operazioni con privilegi.
[SecurityPermissionAttribute(SecurityAction.PermitOnly,
Flags=SecurityPermissionFlag.Execution)]
public void SomeMethod()
{
// The current method and downstream can only execute. They cannot access
// resources or perform other privileged operations.
SomeOtherMethod();
}Nelle sezioni riportate di seguito viene spiegato come utilizzare la protezione dall'accesso di codice per limitare l'accesso a vari tipi di risorse, compresi l'I/O di file, l'accesso al registro eventi o Registro di sistema, ai dati, ai servizi directory, variabili di ambiente, servizi Web e socket.
Per poter eseguire l'I/O di file, i criteri di protezione dall'accesso di codice devono concedere all'assembly l'autorizzazione FileIOPermission. Se viene concessa l'autorizzazione illimitata FileIOPermission, il codice potrà accedere ai file ovunque si trovino nel sistema, in base alla protezione di Windows. È possibile utilizzare un'autorizzazione FileIOPermission limitata per ridurre la capacità di un assembly di eseguire l'I/O di file, specificando ad esempio i diritti di accesso consentiti (lettura, lettura/scrittura e così via).
Un requisito comune è la capacità di limitare l'I/O di file a percorsi di directory specifici, quali la gerarchia di directory dell'applicazione.
Nota: se l'applicazione Web è configurata con Attendibilità media, l'accesso ai file è automaticamente limitato alla gerarchia di directory virtuali dell'applicazione. Per ulteriori informazioni, leggere il modulo 9 "Utilizzo della protezione dall'accesso di codice con ASP.NET".
Configurare l'applicazione con Attendibilità media costituisce un modo per limitare l'I/O di file, nonostante questa limitazione riduca la capacità dell'applicazione di accedere ad altri tipi di risorse. Esistono altri due modi per limitare le capacità di I/O di file del codice:
| • | Utilizzo di PermitOnly per limitare l'I/O di file |
| • | Configurazione dei criteri di protezione dall'accesso di codice per limitare l'I/O di file |
Per limitare l'I/O di file è possibile utilizzare attributi dichiarativi unitamente a SecurityAction.PermitOnly , come illustrato nell'esempio riportato di seguito.
// Allow the code only to read files from c:\YourAppDir
[FileIOPermission(SecurityAction.PermitOnly, Read=@"c:\YourAppDir\")]
[FileIOPermission(SecurityAction.PermitOnly, PathDiscovery=@"c:\YourAppDir\")]
public static string ReadFile(string filename)
{
// Use Path.GetFilePath() to canonicalize the file name
// Use FileStream.OpenRead to open the file
// Use FileStream.Read to access and return the data
}
Nota: il secondo attributo che specifica l'accesso PathDicovery è necessario per la funzione Path.GetFilePath, utilizzata per normalizzare il nome del file di input.
Per evitare di codificare come hard coded la gerarchia di directory dell'applicazione, è possibile utilizzare la sintassi imperativa per la protezione e ricorrere a HttpContext.Current.Request.MapPath(".") per recuperare la directory dell'applicazione Web in fase di runtime. È necessario fare riferimento all'assembly System.Web e aggiungere la corrispondente istruzione using , come illustrato nell'esempio riportato di seguito.
using System.Web;
public static string ReadFile(string filename)
{
string appDir = HttpContext.Current.Request.MapPath(".");
FileIOPermission f = new FileIOPermission(PermissionState.None);
f.SetPathList(FileIOPermissionAccess.Read, appDir);
f.SetPathList(FileIOPermissionAccess.PathDiscovery, appDir);
f.PermitOnly();
// Use Path.GetFilePath() to canonicalize the file name
// Use FileStream.OpenRead to open the file
// Use FileStream.Read to access and return the data
}
Nota: per un'applicazione Windows è possibile sostituire la chiamata a MapPath con una chiamata a Directory.GetCurrentDirectory per ottenere la directory corrente dell'applicazione.
Un amministratore potrà inoltre configurare i criteri di protezione dall'accesso di codice in modo da limitare la capacità del codice di eseguire l'I/O di file oltre la gerarchia di directory virtuali dell'applicazione.
L'amministratore potrebbe, ad esempio, configurare i criteri di protezione dall'accesso di codice a livello di organizzazione o computer in modo da concedere all'assembly un'autorizzazione FileIOPermission limitata. Questo risultato è più facilmente ottenibile se l'assembly contiene un nome sicuro, in quanto l'amministratore potrà avvalersi di questa prova crittograficamente solida nel configurare i criteri. Per gli assembly che non dispongono di un nome sicuro si dovrà utilizzare una forma di prova alternativa. Per ulteriori informazioni su come configurare la protezione dall'accesso di codice per limitare la capacità di I/O di file di un assembly, vedere "Procedura: Utilizzo dei criteri di protezione dall'accesso di codice per vincolare un assembly" nella sezione "Procedure" di questa guida.
Se l'assembly viene chiamato da un'applicazione Web, un approccio migliore consiste nel configurare i criteri di protezione dall'accesso di codice di ASP.NET a livello del dominio applicazione in modo da poter sfruttare $AppDirUrl$, che rappresenta la directory principale virtuale dell'applicazione. Per ulteriori informazioni sulla limitazione dell'I/O di file utilizzando i criteri di protezione dall'accesso di codice di ASP.NET, leggere il modulo 9 "Utilizzo della protezione dall'accesso di codice con ASP.NET."
Come supporto per l'amministratore, se al momento della build sono noti i requisiti precisi dell'assembly per l'I/O dei file, come ad esempio i nomi delle directory, dichiarare FileIOPermission utilizzando una richiesta di autorizzazione dichiarativa, come illustrato nell'esempio riportato di seguito.
[assembly: FileIOPermission(SecurityAction.RequestMinimum, Read=@"C:\YourAppDir")]
L'amministratore potrà vedere questo attributo utilizzando permview.exe. L'ulteriore vantaggio derivante dall'utilizzo di SecurityAction.RequestMinimum è il mancato caricamento dell'assembly nel caso le autorizzazioni non siano sufficienti, preferibile rispetto alla generazione di un'eccezione di protezione del runtime.
Per poter accedere al registro eventi, i criteri di protezione dall'accesso di codice devono concedere all'assembly l'autorizzazione EventLogPermission. Se ciò non avviene, ad esempio perché è in esecuzione nel contesto di un'applicazione Web con attendibilità media, è necessario eseguire il codice di registrazione eventi nel sandbox. Per ulteriori informazioni sull'esecuzione dell'accesso al registro eventi nel sandbox, leggere il modulo 9 "Utilizzo della protezione dall'accesso di codice con ASP.NET."
Se si desidera limitare le azioni del codice wrapper del registro eventi, magari scritto da un altro sviluppatore o organizzazione, è possibile utilizzare attributi dichiarativi unitamente a SecurityAction.PermitOnly, come illustrato nell'esempio riportato di seguito.
L'attributo indicato nell'esempio assicura che il metodo WriteToLog e tutti gli altri metodi da esso chiamati possano accedere esclusivamente al registro eventi del computer locale e non possano cancellare registri o origini degli eventi. Queste operazioni non sono consentite da EventLogPermissionAccess.Instrument.
[EventLogPermission(SecurityAction.PermitOnly,
MachineName=".",
PermissionAccess=EventLogPermissionAccess.Instrument)]
public static void WriteToLog( string message )
Per attivare l'accesso in sola lettura ai registri esistenti utilizzare EventLogPermissionAccess.Browse.
Per documentare i requisiti di autorizzazione del codice e assicurare che l'assembly non possa essere caricato se non dispone di diritti di accesso al registro eventi sufficienti in base a quanto stabilito dai criteri di protezione dall'accesso di codice, aggiungere un attributo EventLogPermissionAttribute a livello dell'assembly, con SecurityAction.RequestMinimum , come illustrato nell'esempio riportato di seguito.
// This attribute indicates that your code requires the ability to access the
// event logs on the local machine only (".") and needs instrumentation access
// which means it can read or write to existing logs and create new event sources
// and event logs
[assembly: EventLogPermissionAttribute(SecurityAction.RequestMinimum,
MachineName=".",
PermissionAccess=
EventLogPermissionAccess.Instrument)]I criteri di protezione dall'accesso di codice devono concedere l'autorizzazione RegistryPermission al codice che accede al Registro di sistema utilizzando la classe Microsoft.Win32.Registry. Questo tipo di autorizzazione può essere utilizzato per limitare l'accesso al Registro di sistema a chiavi e sottochiavi specifiche, oltre che per controllare la capacità del codice di leggere, scrivere o creare chiavi di registro e valori denominati.
Per limitare il codice alla lettura di dati da chiavi specifiche del Registro di sistema è possibile utilizzare RegistryPermissionAttribute unitamente a SecurityAction.PermitOnly. L'attributo indicato di seguito assicura che il codice possa leggere esclusivamente dalla chiave YourApp e relative sottochiavi in HKEY_LOCAL_MACHINE\SOFTWARE.
[RegistryPermissionAttribute(SecurityAction.PermitOnly,
Read=@"HKEY_LOCAL_MACHINE\SOFTWARE\YourApp")]
public static string GetConfigurationData( string key, string namedValue )
{
return (string)Registry.
LocalMachine.
OpenSubKey(key).
GetValue(namedValue);
}Per documentare i requisiti di autorizzazione del codice e assicurare che l'assembly non possa essere caricato se non dispone di diritti di accesso al Registro di sistema sufficienti in base a quanto stabilito dai criteri di protezione dall'accesso di codice, aggiungere un attributo RegistryPermissionAttribute a livello dell'assembly, con SecurityAction.RequestMinimum , come illustrato nell'esempio riportato di seguito.
[assembly: RegistryPermissionAttribute(SecurityAction.RequestMinimum,
Read=@"HKEY_LOCAL_MACHINE\SOFTWARE\YourApp")]Il provider di dati SQL Server di ADO.NET supporta i chiamanti con attendibilità parziale. Gli altri provider di dati, compresi provider OLE DB, Oracle e ODBC, attualmente richiedono chiamanti con attendibilità totale.
Se per la connessione a SQL Server viene utilizzato il provider di dati SQL Server, per il codice di accesso ai dati è necessaria l'autorizzazione SqlClientPermission. È possibile utilizzare SqlClientPermission per limitare l'intervallo consentito di coppie nome/valore che è possibile utilizzare nelle stringhe di connessione passate all'oggetto SqlConnection . Nel codice riportato di seguito, il metodo CheckProductStockLevel è stato potenziato con un ulteriore controllo di protezione per assicurare che non sia possibile evitare di utilizzare una password nella stringa di connessione. Se il codice recupera una stringa di connessione senza password viene generata un'eccezione SecurityException .
[SqlClientPermissionAttribute(SecurityAction.PermitOnly,
AllowBlankPassword=false)]
public static int CheckProductStockLevel(string productCode)
{
// Retrieve the connection string from the registry
string connectionString = GetConnectionString();
. . .
}
Per ulteriori informazioni sull'esecuzione del codice di accesso ai dati nel sandbox in modo che i provider di dati OLE DB ed altri possano essere utilizzati da applicazioni Web con attendibilità parziale, vedere il modulo 9 "Utilizzo della protezione dall'accesso di codice con ASP.NET."
Il codice che utilizza classi dello spazio dei nomi System.DirectoryServices per accedere a servizi directory quali Active Directory deve attualmente disporre dell'attendibilità totale. È tuttavia possibile utilizzare DirectoryServicesPermission per limitare il tipo di accesso e i servizi directory specifici ai quali il codice può connettersi.
Per limitare il codice è possibile utilizzare DirectoryServicesPermissionAttribute unitamente a SecurityAction.PermitOnly. L'attributo indicato di seguito assicura che il codice possa connettersi esclusivamente a un percorso LDAP specifico e sfogliare la directory.
[DirectoryServicesPermissionAttribute(SecurityAction.PermitOnly,
Path="LDAP://rootDSE",
PermissionAccess=DirectoryServicesPermissionAccess.Browse)]
public static string GetNamingContext(string ldapPath)
{
DirectorySearcher dsSearcher = new DirectorySearcher(ldapPath);
dsSearcher.PropertiesToLoad.Add("defaultNamingContext");
dsSearcher.Filter = "";
SearchResult result = dsSearcher.FindOne();
return (string)result.Properties["adsPath"][0];
}Per documentare i requisiti di autorizzazione del codice e assicurare che l'assembly non possa essere caricato se non dispone di diritti di accesso ai servizi directory sufficienti in base a quanto stabilito dai criteri di protezione dall'accesso di codice, aggiungere un attributo DirectoryServicesPermissionAttribute a livello dell'assembly, con SecurityAction.RequestMinimum , come illustrato nell'esempio riportato di seguito.
[assembly: DirectoryServicesPermissionAttribute(SecurityAction.RequestMinimum,
Path="LDAP://rootDSE",
PermissionAccess=DirectoryServicesPermissionAccess.Browse)]I criteri di protezione dall'accesso di codice devono concedere l'autorizzazione EnvironmentPermission al codice che necessita di leggere o scrivere variabili di ambiente utilizzando la classe System.Environment. Questo tipo di autorizzazione può essere utilizzato per limitare l'accesso a specifiche variabili di ambiente denominate.
Per limitare il codice in modo che possa leggere esclusivamente determinate variabili di ambiente è possibile utilizzare EnvironmentPermissionAttribute unitamente a SecurityAction.PermitOnly. Gli attributi indicati di seguito assicurano che il codice possa leggere solo dalle variabili username, userdomain e temp.
[EnvironmentPermissionAttribute(SecurityAction.PermitOnly, Read="username")]
[EnvironmentPermissionAttribute(SecurityAction.PermitOnly, Read="userdomain")]
[EnvironmentPermissionAttribute(SecurityAction.PermitOnly, Read="temp")]
public static string GetVariable(string name)
{
return Environment.GetEnvironmentVariable(name);
}Per documentare i requisiti di autorizzazione del codice e assicurare che l'assembly non possa essere caricato se non dispone di diritti di accesso alle variabili di ambiente sufficienti in base a quanto stabilito dai criteri di protezione dall'accesso di codice, aggiungere un attributo EnvironmentPermissionAttribute a livello dell'assembly, con SecurityAction.RequestMinimum , come illustrato nell'esempio riportato di seguito.
[assembly: EnvironmentPermissionAttribute(SecurityAction.RequestMinimum,
Read="username"),
EnvironmentPermissionAttribute(SecurityAction.RequestMinimum,
Read="userdomain"),
EnvironmentPermissionAttribute(SecurityAction.RequestMinimum,
Read="temp")]I criteri di protezione dall'accesso di codice devono concedere al codice che chiama servizi Web l'autorizzazione WebPermission. WebPermission limita effettivamente l'accesso a tutte le risorse HTTP basate su Internet.
Per limitare i servizi Web ai quali il codice può accedere utilizzare WebPermissionAttribute unitamente a SecurityAction.PermitOnly. Il codice seguente, ad esempio, assicura che il metodo PlaceOrder e gli altri metodi da esso chiamati possano richiamare solo i servizi Web del sito http://host.
[WebPermissionAttribute(SecurityAction.PermitOnly,
ConnectPattern=@"http://somehost/.*")]
[EnvironmentPermissionAttribute(SecurityAction.PermitOnly, Read="USERNAME")]
public static void PlaceOrder(XmlDocument order)
{
PurchaseService.Order svc = new PurchaseService.Order();
// Web service uses Windows authentication
svc.Credentials = System.Net.CredentialCache.DefaultCredentials;
svc.PlaceOrder(order);
}
Nell'esempio riportato in precedenza viene utilizzata la proprietà ConnectPattern della classe WebPermissionAttribute. Ciò consente di fornire un'espressione regolare corrispondente all'intervallo di indirizzi con i quali è possibile stabilire una connessione. L'attributo EnvironmentPermissionAttribute indicato in precedenza è necessario perché il codice utilizza l'autenticazione di Windows e le credenziali predefinite.
Nell'esempio seguente viene illustrato come utilizzare l'attributo Connect per limitare le connessioni a un determinato servizio Web.
[WebPermissionAttribute(SecurityAction.PermitOnly,
Connect=@"http://somehost/order.asmx")]I criteri di protezione dall'accesso di codice devono concedere l'autorizzazione SocketPermission al codice che utilizza direttamente i socket avvalendosi della classe System.Net.Sockets.Socket . Se inoltre il codice utilizza DNS per mappare i nomi degli host agli indirizzi IP, dovrà disporre dell'autorizzazione DnsPermission.
È possibile utilizzare SocketPermission per limitare l'accesso a porte specifiche di host specifici. È altresì possibile limitare la possibilità di utilizzare il socket per accettare connessioni o iniziare connessioni in uscita, oltre che limitare il protocollo di trasporto, ad esempio TCP (Transmission Control Protocol) o UDP (User Datagram Protocol).
Per far sì che il codice possa utilizzare i socket esclusivamente in modo limitato è possibile utilizzare SocketPermissionAttribute unitamente a SecurityAction.PermitOnly. Gli attributi indicati di seguito assicurano che il codice possa connettersi esclusivamente a una porta o host specifico utilizzando il protocollo TCP. Dato che per risolvere i nomi host il codice chiama Dns.Resolve, sarà necessaria anche l'autorizzazione DnsPermission.
[SocketPermissionAttribute(SecurityAction.PermitOnly,
Access="Connect",
Host="hostname",
Port="80",
Transport="Tcp")]
[DnsPermissionAttribute(SecurityAction.PermitOnly, Unrestricted=true)]
public string MakeRequest(string hostname, string message)
{
Socket socket = null;
IPAddress serverAddress = null;
IPEndPoint serverEndPoint = null;
byte[] sendBytes = null, bytesReceived = null;
int bytesReceivedSize = -1, readSize = 4096;
serverAddress = Dns.Resolve(hostname).AddressList[0];
serverEndPoint = new IPEndPoint(serverAddress, 80);
socket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
bytesReceived = new byte[readSize];
sendBytes = Encoding.ASCII.GetBytes(message);
socket.Connect(serverEndPoint);
socket.Send(sendBytes);
bytesReceivedSize = socket.Receive(bytesReceived, readSize, 0);
socket.Close();
if(-1 != bytesReceivedSize)
{
return Encoding.ASCII.GetString(bytesReceived, 0, bytesReceivedSize);
}
return "";
}Per documentare i requisiti di autorizzazione del codice e assicurare che l'assembly non possa essere caricato se non dispone di diritti di accesso ai socket o DNS in base a quanto stabilito dai criteri di protezione dall'accesso di codice, aggiungere un attributo SocketPermissionAttribute e un attributo DnsPermissionAttribute a livello dell'assembly, con SecurityAction.RequestMinimum, come illustrato nell'esempio riportato di seguito.
[assembly: SocketPermissionAttribute(SecurityAction.RequestMinimum,
Access="Connect",
Host="hostname",
Port="80",
Transport="Tcp")
DnsPermissionAttribute(SecurityAction.PermitOnly, Unrestricted=true)]Il codice che chiama API Win32 non gestite o componenti COM richiede l'autorizzazione al codice non gestito, che dovrebbe essere concessa esclusivamente a codice altamente attendibile. Viene definita dal tipo SecurityPermission con la proprietà Flags impostata a SecurityPermissionFlag.UnmanagedCode.
Le linee guida per chiamare codice non gestito riportate di seguito sono complementari a quelle presentate nel modulo 7 "Creazione di assembly protetti."
| • | Utilizzare convenzioni di denominazione per indicare il rischio . |
| • | Richiedere l'autorizzazione al codice non gestito. |
| • | Eseguire le chiamate ad API non gestite nel sandbox. |
| • | Utilizzare SupressUnmanagedCodeSecurityAttribute con cautela. |
Classificare il codice non gestito e prevedere i tipi utilizzati per incapsulare le API non gestite servendosi delle convenzioni di denominazione riportate di seguito.
| • | Protetto. Identifica il codice che non pone problemi di protezione. Può essere chiamato da qualsiasi codice, sia dannoso sia inoffensivo. Ne è un esempio il codice che restituisce il conteggio della frequenza corrente del processore. Alle classi protette è possibile aggiungere l'attributo SuppressUnmanagedCode che disattiva la richiesta di autorizzazione alla protezione dall'accesso di codice in caso di attendibilità totale. [SuppressUnmanagedCode]
class SafeNativeMethods {
[DllImport("user32")]
internal static extern void MessageBox(string text);
} |
| • | Nativo. Si tratta di un tipo di codice non gestito potenzialmente pericoloso, ma protetto con una richiesta di controllo completo dello stack per l'autorizzazione al codice non gestito. Questo avviene implicitamente al livello dell'interoperatività, a meno che il codice non gestito non sia stato soppresso dall'attributo SupressUnmanagedCode. class NativeMethods {
[DllImport("user32")]
internal static extern void FormatDrive(string driveLetter);
} |
| • | Non affidabile. Si tratta di codice non gestito potenzialmente pericoloso con richiesta di protezione per l'autorizzazione al codice non gestito soppressa in maniera dichiarativa. Questi metodi possono essere pericolosi. Tutti i chiamanti di questi metodi devono essere sottoposti a un controllo completo della protezione per assicurare che il loro utilizzo sia protetto, in quanto non viene effettuato alcun controllo dello stack. [SuppressUnmanagedCodeSecurity]
class UnsafeNativeMethods {
[DllImport("user32")]
internal static extern void CreateFile(string fileName);
} |
Con nome sicuro
[assembly: SecurityPermission(SecurityAction.RequestMinimum,
UnmanagedCode=true)]Isolare le chiamata a codice non gestito in assembly specifici e mantenere al minimo il numero di assembly che chiamano codice non gestito. Utilizzare quindi lo schema del sandboxing per assicurare che l'autorizzazione al codice non gestito venga concessa solo a determinati assembly.
| • | Per eseguire nel sandbox codice gestito che chiama codice non gestito
|
Per un esempio di implementazione completo che illustra come chiamare la funzionalità DPAPI Win32 non gestita, vedere "Procedura: creare un'autorizzazione per la crittografia personalizzata" nella sezione "Procedure" di questa guida.
Se l'assembly effettua chiamate a codice non gestito, il sovraccarico associato alla gestione di molte richieste di autorizzazione al codice non gestito può ripercuotersi sulle prestazioni.
In questo caso è possibile utilizzare l'attributo SupressUnmanagedCodeSecurity nella dichiarazione del metodo P/Invoke. Così facendo la richiesta completa dell'autorizzazione al codice non gestito viene sostituita da una richiesta in fase di linking, effettuata una sola volta al momento della compilazione JIT.
Come avviene quando si utilizzano richieste in fase di linking, il codice diviene vulnerabile ad attacchi di tipo luring. Per ridurre il rischio, ricorrere alla soppressione della richiesta di autorizzazione al codice non gestito solo quando nell'assembly si adottano precauzioni adeguate per assicurare che non possa essere forzato ad eseguire operazioni indesiderate. Un esempio di contromisura adeguata è costituito dalla richiesta da parte dell'assembly di un'autorizzazione personalizzata che rispecchi più da vicino le operazioni eseguite dal codice non gestito.
Utilizzare SuppressUnmanagedCodeSecurity con P/Invoke
Il codice riportato di seguito illustra come applicare l'attributo SuppressUnmanagedCodeSecurity alla dichiarazione del metodo P/Invoke (Platform Invocation Services).
public NativeMethods
{
// The use of SuppressUnmanagedCodeSecurity here applies only to FormatMessage
[DllImport("kernel32.dll"), SuppressUnmanagedCodeSecurity]
private unsafe static extern int FormatMessage(
int dwFlags,
ref IntPtr lpSource,
int dwMessageId,
int dwLanguageId,
ref String lpBuffer, int nSize,
IntPtr *Arguments);
}Utilizzare SuppressUnmanagedCodeSecurity con l'interoperabilità COM
Per le chiamate di interoperabilità COM, l'attributo deve essere utilizzato a livello dell'interfaccia, come illustrato nell'esempio riportato di seguito.
[SuppressUnmanagedCodeSecurity]
public interface IComInterface
{
}Non esiste un modo per sapere a priori quali operazioni verranno svolte da un metodo delegato quando lo si richiama. Se l'assembly supporta chiamanti ad attendibilità parziale, è necessario adottare precauzioni aggiuntive quando si richiama un delegato. Per migliorare ulteriormente la protezione si può ricorrere alla protezione dall'accesso di codice.
| • | Prendere in considerazione di limitare le autorizzazioni del delegato . |
| • | Non effettuare l'asserzione di un'autorizzazione prima di chiamare un delegato. |
Le autorizzazioni concesse al codice che chiama il delegato determinano le potenzialità di quest'ultimo. Se il codice sviluppato dispone di maggiori autorizzazioni rispetto al codice che fornisce il delegato, ciò fornisce al chiamante un appiglio per poter eseguire codice con autorizzazioni elevate. Per risolvere il problema è possibile autorizzare il codice esterno, nel punto in cui viene passato il delegato, mediante un'adeguata richiesta di autorizzazione o limitare le autorizzazioni del delegato immediatamente prima di chiamarlo, utilizzando un modificatore dello stack di tipo "deny" o "permit only". Il codice seguente, ad esempio, concede al codice delegato solo l'autorizzazione all'esecuzione per limitarne le potenzialità.
// Delegate definition public delegate void SomeDelegate(); . . . // Permit only execution, prior to calling the delegate. This prevents the // delegate code accessing resources or performing other privileged // operations new SecurityPermission(SecurityPermissionFlag.Execution).PermitOnly(); // Now call the "constrained" delegate SomeDelegate(); // Revert the permit only stack modifier CodeAccessPermission.RevertPermitOnly();
È pericoloso effettuare un'asserzione di un'autorizzazione prima di chiamare un delegato, in quanto non è noto il livello di attendibilità del codice che verrà eseguito quando si richiama il delegato. Il codice che passa il delegato fa parte dello stack di chiamate e può pertanto essere controllato mediante una richiesta di protezione adeguata. Non esistono tuttavia modi che consentano di conoscere il livello di attendibilità o le autorizzazioni concesse al codice delegato in sé.
Per ulteriori informazioni sull'utilizzo protetto dei delegati , vedere la sezione "Delegati" del modulo 7 "Creazione di assembly protetti".
Al codice che supporta la serializzazione deve essere concessa l'autorizzazione SecurityPermission con
l'attributo Flag impostato a SerializationFormatter. Se si sviluppano classi che supportano la serializzazione e il codice supporta chiamanti con attendibilità parziale, è opportuno prendere in considerazione di utilizzare richieste di autorizzazione aggiuntive per imporre limitazioni al tipo di codice che può serializzare lo stato dell'oggetto.
Se si crea una classe che implementa l'interfaccia ISerializable , la quale consente la serializzazione dell'oggetto, è possibile aggiungere una richiesta di autorizzazione all'implementazione di ISerializable.GetObjectData per autorizzare il codice che tenta di serializzare l'oggetto. Questo è particolarmente importante se il codice supporta chiamanti con attendibilità parziale.
Il seguente brano di codice, ad esempio, utilizza una richiesta StrongNameIdentityPermission per assicurare che solo il codice firmato con una determinata chiave privata corrispondente alla chiave pubblica contenuta nella richiesta possa serializzare lo stato dell'oggetto.
[StrongNameIdentityPermission(SecurityAction.Demand,
PublicKey="00240000048...97e85d098615")]
public override void GetObjectData(SerializationInfo info,
StreamingContext context)
Per ulteriori informazioni sull'utilizzo protetto della serializzazione, vedere la sezione "Serializzazione" del modulo 7 " Creazione di assembly protetti".
La protezione dall'accesso di codice consente di limitare le operazioni che il codice può eseguire, oltre che il tipo di codice autorizzato a chiamare il codice sviluppato, nonché di identificare il codice. In ambienti con attendibilità totale, in cui il codice sviluppato e il codice chiamante dispongono di un set di autorizzazioni complete, la protezione dall'accesso di codice è di minore importanza.
Se il codice supporta chiamanti con attendibilità parziale i rischi di protezione sono molto maggiori. In scenari caratterizzati dall'attendibilità parziale, la protezione dall'accesso di codice consente di ridurre alcuni dei rischi aggiuntivi e di limitare il codice con privilegi.
Per ulteriori informazioni, vedere le risorse seguenti:
| • | "Security in .NET: The Security Infrastructure of the CLR Provides Evidence, Policy, Permissions, and Enforcement Services" di Don Box, in MSDN Magazine di settembre 2002, all'indirizzo http://msdn.microsoft.com/msdnmag (in inglese). |
| • | "Security in .NET: Enforce Code Access Rights with the Common Language Runtime" di Keith Brown, in MSDN Magazine di febbraio 2001, all'indirizzo http://msdn.microsoft.com/msdnmag (in inglese). |
| • | .NET Framework Security di LaMacchia, Lange, Lyons, Martin e Price, pubblicato da Addison Wesley (in inglese). |