Protezione nelle librerie di classi

Durante la progettazione delle librerie di classi è necessario valutare attentamente la protezione dell'accesso al codice, al fine di scrivere librerie di classi protette. Quando si scrive una libreria di classi, tenere conto di due principi di protezione: la protezione degli oggetti con autorizzazioni e la scrittura di codice di tipo fully-trusted. Il livello di applicazione di tali principi dipende dalla classe da scrivere. Alcune classi, ad esempio la classe System.IO.FileStream, rappresentano gli oggetti che necessitano di protezione con autorizzazioni. L'implementazione di tali classi gestisce il controllo delle autorizzazioni dei chiamanti e consente solo ai chiamanti autorizzati di eseguire le operazioni per le quali dispongono di autorizzazioni. Lo spazio dei nomi System.Security contiene le classi che consentono di eseguire tali controlli nelle librerie di classi scritte. Il codice della libreria di classi è spesso di tipo fully-trusted o almeno highly-trusted. Poiché il codice della libreria di classi accede spesso alle risorse protette e al codice non gestito, eventuali errori nel codice rappresentano una seria minaccia all'integrità dell'intero sistema di protezione. Per ridurre al minimo tali rischi, seguire le istruzioni descritte in questo argomento per la scrittura del codice delle librerie di classi. Per ulteriori informazioni, vedere Scrittura di librerie di classi protette.

Protezione degli oggetti con autorizzazioni

Le autorizzazioni sono definite per proteggere risorse specifiche. Una libreria di classi che esegue operazioni sulle risorse protette deve gestire l'applicazione di tale protezione. Prima di eseguire operazioni su una richiesta su una risorsa protetta, ad esempio l'eliminazione di un file, il codice della libreria di classi deve in primo luogo controllare che il chiamante disponga dell'autorizzazione all'eliminazione appropriata per la risorsa. Tale controllo viene in genere eseguito per tutti i chiamanti per mezzo di un'analisi dello stack. Se il chiamante dispone dell'autorizzazione, deve essere consentito il completamento dell'azione. Se il chiamante non dispone dell'autorizzazione, non deve essere consentito il completamento dell'azione e deve essere attivata un'eccezione di protezione. La protezione viene implementata in genere nel codice con un controllo dichiarativo o imperativo delle autorizzazioni appropriate.

È importante che le classi proteggano le risorse non solo dall'accesso diretto, ma anche da tutti i possibili tipi di esposizione. Un oggetto file nella cache, ad esempio, è responsabile del controllo delle autorizzazioni in lettura dei file, anche se i dati effettivi vengono recuperati da una cache nella memoria e non si verifica un'operazione nel file effettivo. Questa condizione si verifica in quanto l'effetto della gestione dei dati al chiamante è lo stesso che si verifica quando il chiamante ha eseguito l'operazione di lettura effettiva.

Codice della libreria fully-trusted

Numerose librerie di classi sono implementate come codice fully-trusted che incapsula la funzionalità specifica della piattaforma come oggetti gestiti, ad esempio COM o API di sistema. Il codice fully-trusted può rappresentare un punto di debolezza nella protezione dell'intero sistema. Se, tuttavia, le librerie di classi sono scritte correttamente rispettando le misure di protezione, l'inserimento di un forte carico di protezione su un insieme relativamente ridotto di librerie di classi e la protezione dell'ambiente di esecuzione di base consentono alla parte più ampia del codice gestito di acquisire i vantaggi offerti dalla protezione di tali librerie di classi di base.

In uno scenario di protezione comune della libreria di classe, una classe fully-trusted espone una risorsa che viene protetta da un'autorizzazione; l'accesso alla risorsa viene eseguito da un'interfaccia API del codice nativo. Un esempio tipico di questo tipo di risorsa è un file. La classe File utilizza un'interfaccia API nativa per eseguire le operazioni sui file, ad esempio l'eliminazione. Per proteggere la risorsa, viene eseguita la procedura indicata di seguito.

  1. Un chiamante richiede l'eliminazione del file c:\test.txt tramite la chiamata al metodo File.Delete.
  2. Il metodo Delete crea un oggetto autorizzazione che rappresenta l'autorizzazione delete c:\test.txt.
  3. Il codice della classe File controlla che a tutti i chiamanti nello stack sia stata concessa l'autorizzazione richiesta; in caso contrario, viene attivata un'eccezione di protezione.
  4. La classe File esegue l'asserzione di FullTrust per richiamare il codice nativo, in quanto i chiamanti potrebbero non disporre dell'autorizzazione.
  5. La classe File utilizza un'interfaccia API nativa per eseguire l'operazione di eliminazione del file.
  6. La classe File ritorna al chiamante e la richiesta di eliminazione del file viene completata correttamente.

Precauzioni per il codice highly-trusted

Al codice in una libreria di classi di tipo trusted (attendibile) sono state concesse le autorizzazioni che non sono disponibili alla maggior parte del codice dell'applicazione. Inoltre un assembly potrebbe contenere classi che non necessitano di autorizzazioni speciali ma a cui tali autorizzazioni vengono concesse in quanto l'assembly contiene altre classi che le richiedono. In questi casi il codice viene esposto a un punto di debolezza nella protezione del sistema. È quindi necessario prestare particolare attenzione quando si scrive codice highly-trusted o fully-trusted.

Progettare il codice di tipo trusted (attendibile) in modo che possa essere chiamato dal codice semi-trusted nel sistema senza creare punti di debolezza della protezione. Le risorse sono protette in genere da un'analisi dello stack di tutti i chiamanti. Se un chiamante non dispone di autorizzazioni sufficienti, il tentativo di accesso viene bloccato. Tuttavia ogni volta che il codice di tipo trusted esegue l'asserzione di un'autorizzazione, diventa responsabile del controllo delle autorizzazioni richieste. In genere un'asserzione deve essere eseguita dopo un controllo dell'autorizzazione del chiamante come descritto in precedenza in questo argomento. Inoltre il numero di asserzioni di autorizzazioni di livello superiore deve essere ridotto al minimo per limitare il rischio di un'esposizione non desiderata.

Al codice fully-trusted vengono concesse in modo implicito tutte le altre autorizzazioni. Inoltre è consentito violare le regole sulla indipendenza dai tipi e sull'uso degli oggetti. Indipendentemente dalla protezione delle risorse, qualsiasi aspetto dell'interfaccia di programmazione che potrebbe violare l'indipendenza dai tipi o consentire l'accesso ai dati normalmente non disponibili al chiamante può generare un problema di protezione.

Prestazioni

I controlli della protezione richiedono il controllo dello stack per verificare le autorizzazioni di tutti i chiamanti. In base alla profondità dello stack, queste operazioni possono risultare molto impegnative. Se un'operazione è effettivamente costituita da alcune azioni a un livello inferiore che richiedono i controlli di protezione, le prestazioni possono migliorare notevolmente se le autorizzazioni dei chiamanti vengono controllate una volta, quindi viene eseguita l'asserzione dell'autorizzazione necessaria prima di eseguire le azioni. L'asserzione interromperà il percorso stack in modo che il controllo si interromperà in quel punto e verrà eseguito. Questa tecnica determina in genere un miglioramento delle prestazioni se tre o più controlli di autorizzazioni possono essere eseguiti contemporaneamente.

Riepilogo degli aspetti relativi alla protezione della libreria di classi

  • Qualsiasi libreria di classi che utilizza le risorse protette deve garantire che l'operazione venga eseguita solo nell'ambito delle autorizzazioni dei propri chiamanti.
  • L'asserzione delle autorizzazioni deve essere eseguita solo se necessario e deve essere preceduta dai controlli delle autorizzazioni appropriati.
  • Per migliorare le prestazioni, aggregare le operazioni che richiederanno controlli della protezione e provare a utilizzare l'asserzione per limitare il percorso stack senza compromettere la protezione.
  • Essere consapevoli che un chiamante semi-trusted non autorizzato potrebbe utilizzare una classe per aggirare la protezione.
  • Non presumere che il codice verrà chiamato solo da chiamanti con determinate autorizzazioni.
  • Non definire interfacce non type-safe che potrebbero essere utilizzate per aggirare altrove la protezione.
  • Non esporre una funzionalità in una classe che consente a un chiamante semi-trusted di avvantaggiarsi della maggiore attendibilità della classe.

Vedere anche

Istruzioni di progettazione per gli sviluppatori di librerie di classi | Scrittura di librerie di classi protette | Protezione dall'accesso di codice | Operazioni sulle stringhe che tengono conto delle impostazioni relative a lingua e protezione