Share via


Utilizar el método Assert

Actualización: noviembre 2007

Assert es un método al que se puede llamar en las clases de permiso de acceso a código y en la clase PermissionSet. Se puede utilizar Assert para habilitar el código (y los llamadores indirectos) de forma que realice las acciones para las que tiene permiso, pero para las que sus llamadores pueden no tenerlo. Una aserción de seguridad cambia el proceso normal que realiza el motor en tiempo de ejecución durante una comprobación de seguridad. Cuando se afirma un permiso, se indica al sistema de seguridad que no compruebe si los llamadores del código tienen el permiso afirmado.

Precaución:

Use las aserciones con cuidado, ya que pueden abrir brechas en la seguridad y minar el mecanismo del motor en tiempo de ejecución para imponer las restricciones de seguridad.

Las aserciones son de utilidad cuando una biblioteca llama a código no administrado o realiza una llamada que requiere un permiso que no está claramente relacionado con el uso previsto de la biblioteca. Por ejemplo, todo código administrado que llama a código no administrado debe tener un permiso SecurityPermission con el indicador UnmanagedCode especificado. De manera predeterminada, no se concede este permiso al código que no procede del equipo local, como el que se descarga de la intranet local. Por tanto, para que el código descargado de la intranet local pueda llamar a una biblioteca que utilice código no administrado, debe tener el permiso declarado por la biblioteca. Además, algunas bibliotecas pueden realizar llamadas invisibles para los llamadores y requerir permisos especiales.

Las aserciones se pueden utilizar también cuando el código obtiene acceso a un recurso de manera totalmente oculta para los llamadores. Supongamos, por ejemplo, que su biblioteca adquiere información de una base de datos pero, en el proceso, también lee información del Registro del equipo. Dado que los programadores que utilicen la biblioteca no tienen acceso a su origen, no pueden saber que el código requiere RegistryPermission para poder utilizar su código. En este caso, si decide que no es razonable o necesario exigir que los llamadores de su código tengan permiso de acceso al Registro, podrá afirmar el permiso para leer el Registro. En este caso, es oportuno que la biblioteca afirme el permiso para que los llamadores que no tengan RegistryPermission puedan utilizarla.

La aserción afecta al recorrido de pila sólo si el permiso afirmado y un permiso exigido por un llamador indirecto son del mismo tipo y si el permiso exigido es un subconjunto del permiso afirmado. Por ejemplo, si afirma FileIOPermission para leer todos los archivos de la unidad C y se realiza una petición indirecta de FileIOPermission para leer los archivos de C:\Temp, la aserción podrá afectar al recorrido de pila; sin embargo, si se tratase de una petición de FileIOPermission para escribir en la unidad C, la aserción no tendría efecto.

Para realizar aserciones, el código debe recibir tanto el permiso que se afirma como el objeto SecurityPermission que representa el derecho de realizar aserciones. Aunque se puede afirmar un permiso que el código no ha recibido, la afirmación no tendría ningún sentido porque se produciría un error en la comprobación de seguridad antes de que la afirmación pudiese hacer que fuese correcta.

En la ilustración siguiente se muestra lo que sucede cuando se utiliza Assert. Supongamos que las siguientes instrucciones son verdaderas sobre los ensamblados A, B, C, E y F, y dos permisos, P1 y P1A:

  • P1A representa el derecho de leer archivos .txt en la unidad C.

  • P1 representa el derecho de leer todos los archivos de la unidad C.

  • P1A y P1 son ambos tipos de FileIOPermission, y P1A es un subconjunto de P1.

  • A los ensamblados E y F se les ha concedido el permiso P1A.

  • El ensamblado C ha recibido el permiso P1.

  • A los ensamblados A y B no se les ha concedido el permiso P1 ni P1A.

  • El método A está incluido en el ensamblado A, el método B en el ensamblado B, y así sucesivamente.

Utilizar Assert

En este escenario, el método A llama a B, B llama a C, C llama a E y E llama a F. El método C declara el permiso para leer los archivos de la unidad C (permiso P1) y el método E exige el permiso de lectura de los archivos .txt de la unidad C (permiso P1A). Cuando se detecta la petición en F en tiempo de ejecución, se realiza un recorrido de pila para comprobar los permisos de todos los llamadores de F, empezando por E. E ha recibido el permiso P1A, por lo que el recorrido de pila procede a examinar los permisos de C, donde se descubre la aserción de C. Dado que el permiso requerido (P1A) es un subconjunto del permiso afirmado (P1), el recorrido de pila se detiene y la comprobación de seguridad se realiza automáticamente de manera correcta. No importa que los ensamblados A y B no hayan recibido el permiso P1A. Al afirmar P1, el método C garantiza que sus llamadores puedan obtener acceso al recurso protegido por P1, incluso si los llamadores no han recibido permiso para obtener acceso a ese recurso.

Si diseña una biblioteca de clases y una clase obtiene acceso a un recurso protegido, en la mayoría de los casos se debe realizar una petición de seguridad que exija que los llamadores de la clase tengan el permiso correcto. Si, después, la clase realiza una operación para la que sabe que la mayoría de los llamadores no tendrán permiso, y si desea asumir la responsabilidad de dejar que estos llamadores llamen al código, podrá afirmar el permiso mediante una llamada al método Assert en un objeto de permiso que represente la operación que el código está realizando. Al utilizar Assert de este modo, permite que los llamadores que normalmente no podrían llamar a su código puedan hacerlo. Por tanto, si afirma un permiso, debe asegurarse de que se realizan previamente las comprobaciones de seguridad pertinentes para evitar que su componente se utilice de forma indebida.

Supongamos, por ejemplo, que una clase de biblioteca de total confianza tiene un método que elimina archivos. Obtiene acceso al archivo mediante una llamada a una función Win32 no administrada. Un llamador invoca el método Delete de su código y pasa el nombre del archivo que se va a eliminar, C:\Test.txt. Dentro del método Delete, el código crea un objeto FileIOPermission que representa el acceso de escritura a C:\Test.txt. (Es necesario el acceso de escritura para eliminar un archivo.) A continuación, el código invoca una comprobación de seguridad imperativa mediante una llamada al método Demand del objeto FileIOPermission. Si uno de los llamadores de la pila de llamadas no dispone de este permiso, se producirá una excepción SecurityException. Si no se produce ninguna excepción, significa que todos los llamadores tienen derecho de acceso a C:\Test.txt. Como, en su opinión, la mayoría de los llamadores no tendrán permiso de acceso a código no administrado, el código creará un objeto SecurityPermission que represente el derecho de llamar a código no administrado y llamará al método Assert del objeto. Por último, llamará a la función Win32 no administrada para eliminar C:\Text.txt y devolverá el control al llamador.

Precaución:

Debe asegurarse de que su código no utilice aserciones cuando puede ser utilizado por otro código para obtener acceso a un recurso que está protegido por el permiso que está afirmando. Por ejemplo, en código que escribe en un archivo cuyo nombre es especificado por el llamador como parámetro, no declararía el permiso FileIOPermission para escribir en archivos porque su código podría ser utilizado indebidamente por terceros.

Al utilizar la sintaxis de seguridad imperativa, llamar al método Assert en varios permisos en el mismo método hará que se genere una excepción de seguridad. En su lugar, cree un objeto PermissionSet, pásele cada uno de los permisos que desee invocar y, después, llame al método Assert en el objeto PermissionSet. Puede llamar más de una vez al método Assert al utilizar la sintaxis de seguridad declarativa.

En el ejemplo siguiente se muestra una sintaxis declarativa para reemplazar las comprobaciones de seguridad con el método Assert. Observe que la sintaxis FileIOPermissionAttribute utiliza dos valores: una enumeración SecurityAction y la ubicación del archivo o directorio al que se debe conceder el permiso. La llamada a Assert hace que se realicen correctamente las peticiones de acceso a C:\Log.txt, aunque no se comprueben los permisos de acceso al archivo de los llamadores.

[Visual Basic]

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
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();
      }
   }
} 

En los siguientes fragmentos de código se muestra una sintaxis imperativa para reemplazar las comprobaciones de seguridad con el método Assert. En este ejemplo, se declara una instancia del objeto FileIOPermission. Se pasa FileIOPermissionAccess.AllAccess al constructor para definir el tipo de acceso permitido, seguido de una cadena que describe la ubicación del archivo. Tras definir el objeto FileIOPermission, sólo necesita llamar al método Assert para reemplazar la comprobación de seguridad.

[Visual Basic]

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 
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();
      }
   }
}

Vea también

Conceptos

Invalidar comprobaciones de seguridad

Peticiones de seguridad

Referencia

PermissionSet

SecurityPermission

FileIOPermission

SecurityAction

Otros recursos

Extender metadatos mediante atributos

Seguridad de acceso a código