Assert

Assert è un metodo che può essere chiamato nelle classi di autorizzazione di accesso al codice e nella classe PermissionSet. È possibile utilizzare Assert per consentire al codice, ed ai chiamanti downstream di eseguire le operazioni per cui il codice è autorizzato, anche qualora i chiamanti a monte del codice siano privi di tale autorizzazione. Un'asserzione di protezione consente di modificare il normale processo eseguito dal runtime durante un controllo di protezione. Mediante l'asserzione di un'autorizzazione si impone al sistema di protezione di non eseguire il controllo dei chiamanti del codice relativamente all'autorizzazione oggetto dell'asserzione.

Attenzione   Utilizzare con cautela le asserzioni, in quanto possono provocare l'indebolimento del sistema di protezione e compromettere il meccanismo runtime per la pretesa delle restrizioni di protezione.

Le asserzioni risultano utili nelle situazioni in cui una libreria chiama codice non gestito o effettua una chiamata che richiede un'autorizzazione non direttamente correlata all'utilizzo previsto della libreria. In tutto il codice gestito che consente di chiamare codice non gestito, ad esempio, devono essere specificati una SecurityPermission e un flag UnmanagedCode. Per impostazione predefinita, il codice che non ha origine nel computer locale, ad esempio quello scaricato dalla rete Intranet locale, non otterrà questa autorizzazione. Perché il codice scaricato dalla rete Intranet locale consente di chiamare una libreria in cui si utilizza codice non gestito, sarà quindi necessario eseguire un'asserzione dell'autorizzazione a livello di libreria. È inoltre possibile che alcune librerie effettuino chiamate non visualizzate ai chiamanti e che richiedano autorizzazioni specifiche.

Le asserzioni possono anche essere utilizzate nelle situazioni in cui il codice accede a una risorsa in modo completamente invisibile ai chiamanti. Si supponga, ad esempio, che la libreria acquisisca informazioni da un database, ma durante l'elaborazione legga ulteriori informazioni nel Registro di sistema del computer. Dal momento che gli sviluppatori che utilizzano la libreria non hanno accesso al codice sorgente, non possono in alcun modo sapere che per potere utilizzare il codice è necessaria l'autorizzazione RegistryPermission. In questo caso, se si stabilisce che non è ragionevole o necessario imporre che i chiamanti del codice dispongano di un'autorizzazione per accedere al Registro di sistema, è possibile effettuare un'asserzione di autorizzazione in relazione alla lettura del Registro di sistema. È consigliabile, in questa situazione, che la libreria effettui l'asserzione dell'autorizzazione in modo che i chiamanti privi di RegistryPermission possano comunque utilizzarla.

L'asserzione influisce sull'elaborazione dello stack solo se l'autorizzazione che ne è oggetto e l'autorizzazione pretesa da un chiamante downstream sono dello stesso tipo e se l'autorizzazione pretesa è un sottoinsieme dell'autorizzazione oggetto dell'asserzione. Se, ad esempio, si effettua un'asserzione di FileIOPermission per la lettura di tutti i file contenuti nell'unità C e viene generata una pretesa downstream di FileIOPermission per la lettura dei file contenuti nella cartella C:\Temp, l'asserzione può influire sull'elaborazione dello stack. Se invece la pretesa di FileIOPermission riguarda la scrittura sull'unità C, l'asserzione non avrà effetto.

Perché sia possibile effettuare asserzioni, è necessario che il codice disponga sia dell'autorizzazione oggetto dell'asserzione che dell'autorizzazione SecurityPermission che rappresenta il diritto di effettuare asserzioni. Benché sia possibile effettuare l'asserzione di un'autorizzazione non concessa al codice, tale operazione non avrebbe alcun significato, poiché il controllo di protezione avrebbe esito negativo ancor prima che l'asserzione ne potesse garantire la riuscita.

Nell'illustrazione che segue vengono mostrate le fasi dell'utilizzo del metodo Assert. Si supponga che le seguenti affermazioni siano valide per gli assembly A, B, C, E e F e per le due autorizzazioni P1 e P1A:

  • P1A rappresenta il diritto di leggere i file TXT contenuti nell'unità C.
  • P1 rappresenta il diritto di leggere tutti i file contenuti nell'unità C.
  • P1A e P1 sono entrambe FileIOPermissions e P1A è un sottoinsieme di P1.
  • Agli assembly E ed F è stata concessa l'autorizzazione P1A.
  • All'assembly C è stata concessa l'autorizzazione P1.
  • Agli assembly A e B non è stata concessa né l'autorizzazione P1 né l'autorizzazione P1A.
  • Nell'assembly A è contenuto il metodo A, nell'assembly B è contenuto il metodo B e così via.

Utilizzo di Assert

In questo scenario, il metodo A chiama B, B chiama C, C chiama E ed E chiama F. Il metodo C effettua un'asserzione dell'autorizzazione alla lettura dei file contenuti nell'unità C (autorizzazione P1) e il metodo E impone l'autorizzazione alla lettura dei file TXT contenuti nell'unità C (autorizzazione P1A). Quando in fase di esecuzione viene rilevata la pretesa in F, comincia l'analisi dello stack per controllare le autorizzazioni di tutti i chiamanti di F a partire da E. Dal momento che E dispone dell'autorizzazione P1A, l'analisi dello stack procede con l'esame delle autorizzazioni di C, dove viene rilevata l'asserzione di C. Poiché l'autorizzazione pretesa (P1A) è un sottoinsieme dell'autorizzazione oggetto dell'asserzione (P1), l'elaborazione dello stack si interrompe e automaticamente il controllo di protezione ha esito positivo. Non è importante che gli assembly A e B non abbiano ottenuto l'autorizzazione P1A: con l'asserzione di P1, il metodo C garantisce che i chiamanti siano in grado di accedere alla risorsa protetta da P1, anche se non è stata loro concessa la relativa autorizzazione.

Se si progetta una libreria di classi e una classe accede a una risorsa protetta, nella maggior parte dei casi sarà necessario generare una pretesa di protezione che imponga ai chiamanti della classe il possesso dell'autorizzazione appropriata. Se successivamente la classe esegue un'operazione per la quale si è certi che la maggior parte dei chiamanti della classe non disponga di autorizzazioni e si è disposti a consentire loro di chiamare il codice, è possibile effettuare un'asserzione dell'autorizzazione chiamando il metodo Assert su un oggetto autorizzazione che rappresenta l'operazione eseguita dal codice. Utilizzando il metodo Assert in questo modo si consente di chiamare il codice a chiamanti che normalmente non disporrebbero dell’autorizzazione necessaria per farlo. Quando si effettua quindi l'asserzione di un'autorizzazione, è necessario assicurarsi di avere precedentemente eseguito gli opportuni controlli di protezione per impedire l'utilizzo improprio del componente.

Si supponga, ad esempio, che una classe di libreria altamente attendibile disponga di un metodo per l'eliminazione di file. L'accesso al file viene effettuato chiamando una funzione Win32 non gestita. Un chiamante richiama il metodo Delete del codice, passando il nome del file da eliminare, C:\Test.txt. All'interno del metodo Delete, il codice consente di creare un oggetto FileIOPermission che rappresenta l'accesso in scrittura a C:\Test.txt. L'accesso in scrittura è necessario per l'eliminazione del file. Viene quindi richiamato un controllo di protezione imperativo chiamando il metodo Demand dell'oggetto FileIOPermission. Se uno dei chiamanti compresi nello stack di chiamate non dispone di questa autorizzazione, viene generata una SecurityException. Se non viene generata alcuna eccezione, tutti i chiamanti avranno il diritto di accedere a C:\Test.txt. Dal momento che si prevede che la maggior parte dei chiamanti non disporrà dell'autorizzazione per l'accesso al codice non gestito, viene creato un oggetto SecurityPermission che rappresenta il diritto di chiamare codice non gestito. Viene quindi chiamato il metodo Assert di tale oggetto. Viene poi chiamata la funzione Win32 non gestita per eliminare C:\Text.txt e infine il controllo viene restituito al chiamante.

Attenzione   È necessario assicurarsi che non vengano utilizzate asserzioni in situazioni in cui è possibile che il codice venga utilizzato da altro codice per accedere a una risorsa protetta dall'autorizzazione oggetto dell'asserzione. È ad esempio necessario che nel codice che consente di scrivere in un file il cui nome è specificato come parametro dal chiamante non venga effettuata l'asserzione di FileIOPermission per la scrittura nei file, poiché il codice sarebbe esposto a un eventuale utilizzo improprio da parte di terzi.

Chiamando il metodo Assert su più autorizzazioni nello stesso metodo, potrebbero verificarsi comportamenti imprevedibili e indesiderati. Si consiglia invece di creare un oggetto PermissionSet, passare a tale oggetto le singole autorizzazioni che si desidera richiamare e infine chiamare sull'oggetto il metodo Assert.

Nell'esempio seguente viene illustrato l'utilizzo della sintassi dichiarativa per eseguire l'override dei controlli di protezione mediante il metodo Assert. Si noti che la sintassi di FileIOPermissionAttribute assume due valori: un'enumerazione SecurityAction e la posizione del file o della directory per i quali è necessario che venga concessa l'autorizzazione. La chiamata di Assert determina l'esito positivo delle pretese di accesso a C:\Log.txt, anche se i chiamanti non vengono sottoposti a controllo per stabilire se dispongono delle autorizzazioni necessarie per l'accesso.

Option Explicit
Option Strict

Imports System
Imports System.IO
Imports System.Security.Permissions

Namespace LogUtil
   Public Class Log
      Public Sub New()

      End Sub

     <FileIOPermission(SecurityAction.Assert, All := "C:\Log.txt")> Public Sub 
      MakeLog()
         Dim TextStream As New StreamWriter("C:\Log.txt")
         TextStream.WriteLine("This  Log was created on {0}", DateTime.Now) '
         TextStream.Close()
      End Sub
   End Class
End Namespace
[C#]
namespace LogUtil
{
   using System;
   using System.IO;
   using System.Security.Permissions;

   public class Log
   {
      public Log()
      {    
      }   
      [FileIOPermission(SecurityAction.Assert, All = @"C:\Log.txt")]
      public void MakeLog()
      {   
         StreamWriter TextStream = new StreamWriter(@"C:\Log.txt");
         TextStream.WriteLine("This  Log was created on {0}", DateTime.Now);
         TextStream.Close();
      }
   }
} 

Nei frammenti di codice seguenti viene illustrato l'utilizzo della sintassi imperativa per eseguire l'override dei controlli di protezione mediante il metodo Assert. In tale esempio viene dichiarata un'istanza dell'oggetto FileIOPermission. Al relativo costruttore viene passato FileIOPermissionAccess.Read per definire il tipo di accesso consentito, seguito da una stringa che specifica la posizione del file. Una volta definito l'oggetto FileIOPermission, sarà sufficiente chiamarne il metodo Assert per eseguire l'override dei controlli di protezione.

Option Explicit
Option Strict
Imports System
Imports System.IO
Imports System.Security.Permissions
Namespace LogUtil
   Public Class Log
      Public Sub New()
      End Sub 'New
      
      Public Sub MakeLog()
         Dim FilePermission As New FileIOPermission(FileIOPermissionAccess.AllAccess, "C:\Log.txt")
         FilePermission.Assert()
         Dim TextStream As New StreamWriter("C:\Log.txt")
         TextStream.WriteLine("This  Log was created on {0}", DateTime.Now)
         TextStream.Close()
      End Sub
   End Class
End Namespace 
[C#]
namespace LogUtil
{
   using System;
   using System.IO;
   using System.Security.Permissions;

   public class Log
   {
      public Log()
      {    
      }   
      public void MakeLog()
      {
         FileIOPermission FilePermission = new FileIOPermission(FileIOPermissionAccess.AllAccess,@"C:\Log.txt"); 
         FilePermission.Assert();
         StreamWriter TextStream = new StreamWriter(@"C:\Log.txt");
         TextStream.WriteLine("This  Log was created on {0}", DateTime.Now);
         TextStream.Close();
      }
   }
}

Vedere anche

Estensione di metadati mediante attributi | Override dei controlli di protezione | Protezione dall'accesso di codice | Assert | PermissionSet | SecurityPermission | Pretese di protezione | FileIOPermission | SecurityAction