Otimizações de segurança

Verificações de segurança podem causar problemas de desempenho para alguns aplicativos. Existem duas técnicas de otimização que você pode usar para melhorar o desempenho. Uma técnica que combina as exigências de segurança; o outro suprime as solicitações de permissão para chamar código não gerenciado. Embora essas técnicas podem melhorar o desempenho do seu aplicativo, eles podem também tornar seu aplicativo vulnerável a explorações de segurança. Antes de usar essas técnicas de otimização, você deve tomar as seguintes precauções:

  • Execute o Diretrizes para Codificação Segura para código gerenciado.

  • Compreender as implicações de segurança das otimizações e usar outros métodos para proteger seu aplicativo conforme apropriado.

  • Implemente as otimizações de segurança mínima necessárias para melhorar o desempenho do aplicativo.

Depois de otimizar seu código, você deve testar o código otimizado para determinar se realmente melhorou seu desempenho. Caso contrário, você deve remover as otimizações de segurança para ajudar a evitar falhas na segurança inadvertida.

Observação de cuidadoCuidado

Otimização de segurança requer que você altere a segurança de acesso de código padrão.Para evitar a introdução de vulnerabilidades de segurança em seu código, certifique-se de que você entender as implicações de segurança de técnicas de otimização antes de usá-los.

Combinando as exigências de segurança

Para otimizar o código que faz com que as demandas de segurança, você pode, em algumas situações, usar uma técnica para combinar as demandas.

Por exemplo, se:

  • seu código realiza um número de operações dentro de um único método, e

  • ao realizar cada uma dessas operações, seu código chama uma biblioteca de classe gerenciada que exige que o seu código deve ter a mesma permissão em cada chamada para a biblioteca

em seguida:

  • Você pode modificar seu código para realizar uma demanda e um Assert dessa permissão para reduzir a sobrecarga incorrida pelas demandas de segurança.

Se a profundidade da pilha de chamadas acima o método for grande, usando essa técnica pode resultar em um ganho de desempenho significativos.

Para ilustrar como isso funciona, suponha que o método m executa operações de 100. Cada operação chama uma biblioteca que faz uma demanda de segurança que exigem o seu código e todos os chamadores ter a permissão de X. Devido a exigências de segurança de cada operação faz com que o tempo de execução movimentar a pilha de chamada toda examinando as permissões do chamador, para determinar se a permissão de X, na verdade, foi concedido a cada chamador. Se a pilha de chamadas acima o método m é n níveis de profundidade, 100n as comparações são necessárias.

Para otimizar, você pode fazer o seguinte método m:

  • X, o que resulta em uma pilha de execução o tempo de execução andar de demanda (de profundidade n) para garantir que todos os chamadores realmente tenham permissão X.

  • Em seguida, declarar a permissão X, que faz com que o subseqüentes de stack walks interromper o método m e tiver êxito, reduzindo o número de comparações de permissão por 99n.

No exemplo de código a seguir, o GetFileCreationTime leva uma representação de seqüência de caracteres de um diretório como um parâmetro de método e exibe a data de criação e o nome de cada arquivo no diretório. Estática File.GetCreationTime método lê as informações dos arquivos, mas requer uma demanda e uma pilha de passar para cada arquivo ele leituras. O método cria uma nova instância de FileIOPermission objeto, realiza uma demanda para verificar as permissões de todos os chamadores na pilha e, em seguida, declara a permissão, se a demanda for bem-sucedida. Se a solicitação for bem-sucedida, apenas um stack walk é efetuada, e o método lê o tempo de criação de todos os arquivos no diretório do passado.

using System;
using System.IO;
using System.Security;
using System.Security.Permissions;

namespace OptimizedSecurity
{
   public class FileUtil
   {
      public FileUtil()
      {
      }

      public void GetFileCreationTime(string Directory)
      {
         //Initialize DirectoryInfo object to the passed directory. 
         DirectoryInfo DirFiles = new DirectoryInfo(Directory);

         //Create a DateTime object to be initialized below.
         DateTime TheTime;

         //Get a list of files for the current directory.
         FileInfo[] Files = DirFiles.GetFiles();
         
         //Create a new instance of FileIOPermission with read 
         //permission to the current directory.
         FileIOPermission FilePermission = new FileIOPermission(FileIOPermissionAccess.Read, Directory);

         try
         {
            //Check the stack by making a demand.
            FilePermission.Demand();

            //If the demand succeeded, assert permission and 
            //perform the operation.
            FilePermission.Assert();

            for(int x = 0 ; x<= Files.Length -1 ; x++)
            {
               TheTime = File.GetCreationTime(Files[x].FullName);
               Console.WriteLine("File: {0} Created: {1:G}", Files[x].Name,TheTime );
            }
            // Revert the Assert when the operation is complete.
            CodeAccessPermission.RevertAssert();
         }
         //Catch a security exception and display an error.
         catch(SecurityException)
         {
            Console.WriteLine("You do not have permission to read this directory.");
         }                            
      }
   }
}
Option Explicit
Option Strict
Imports System
Imports System.IO
Imports System.Security
Imports System.Security.Permissions
Namespace OptimizedSecurity
   Public Class FileUtil      
      Public Sub New()
      End Sub
      Public Sub GetFileCreationTime(directory As String)
         'Initialize DirectoryInfo object to the passed directory. 
         Dim dirFiles As New DirectoryInfo(directory)
         'Create a DateTime object to be initialized below.
         Dim theTime As DateTime
         'Get a list of files for the current directory.
         Dim files As FileInfo() = dirFiles.GetFiles()
         'Create a new instance of FileIOPermission with read 
         'permission to the current directory.
         Dim filePermission As New FileIOPermission(FileIOPermissionAccess.Read, Directory)
         Try
            'Check the stack by making a demand.
            filePermission.Demand()
            'If the demand succeeded, assert permission and 
            'perform the operation.
            filePermission.Assert()
            Dim x As Integer
            For x = 0 To Files.Length - 1
               theTime = file.GetCreationTime(files(x).FullName)
               Console.WriteLine("File: {0} Created: {1:G}", files(x).Name, theTime)
            Next x
            ' Revert the Assert when the operation is complete.
            CodeAccessPermission.RevertAssert()
         'Catch a security exception and display an error.
         Catch
            Console.WriteLine("You do not have permission to read this directory.")
         End Try
      End Sub
   End Class
End Namespace

Se a demanda no exemplo anterior for bem-sucedida, todos os arquivos e sua data de criação e a hora são exibidos para o diretório passado. Se a demanda falhar, a exceção de segurança é interceptada e a seguinte mensagem é exibida no console:

You do not have permission to read this directory.

Suprimindo as demandas de permissão de código não gerenciado

Uma otimização especial está disponível para o código tem permissão para chamar código não gerenciado. Essa otimização permite que seu código gerenciado chamar código não gerenciado, sem incorrer em sobrecarga de uma stack walk. Declarar a permissão de código não gerenciado pode encurtar a stack walk, mas a otimização, descrita neste tópico pode eliminá-lo inteiramente. (Consulte SecurityPermission para obter mais informações sobre a permissão para chamar código não gerenciado.)

Normalmente, uma chamada para código não gerenciado gera uma demanda de permissão de código não gerenciado, o que resulta em uma movimentação de pilha que determina se todos os chamadores têm permissão para chamar código não gerenciado. Aplicar o atributo personalizado SuppressUnmanagedCodeSecurityAttribute para o método que chama código não gerenciado suprime a demanda. Este atributo substitui toda a stack walk em tempo de execução com uma seleção que só verifica as permissões do chamador imediato no momento de link. Na verdade, usar este atributo cria uma porta aberta em código não gerenciado. Somente o código tem permissão de código não gerenciado pode usar esse atributo; Caso contrário, ele não tem efeito.

Observação de cuidadoCuidado

Use o SuppressUnmanagedCodeSecurityAttribute o atributo somente com muito cuidado.Uso incorreto desse atributo pode criar vulnerabilidades de segurança.O SuppressUnmanagedCodeSecurityAttribute atributo nunca deve ser usado para permitir que código menos confiável (código que não tem permissão de código não gerenciado) para chamar código não gerenciado.

Este atributo melhor é aplicado somente a pontos de entrada declarado em particular para o código não gerenciado para que o código em outros assemblies não poderá acessar e aproveitar a supressão de segurança. Normalmente, o código gerenciado e altamente confiável que usa esse atributo primeiro exige a alguma permissão de chamadores antes de invocar o código não gerenciado em nome do chamador.

A exemplo a seguir mostra a SuppressUnmanagedCodeSecurityAttribute atributo aplicado a um ponto de entrada privada.

<SuppressUnmanagedCodeSecurityAttribute()> Private Declare Sub 
EntryPoint Lib "some.dll"(args As String)
[SuppressUnmanagedCodeSecurityAttribute()]
[DllImport("some.dll")]
private static extern void EntryPoint(string args);

No caso raro de código não gerenciado, é completamente seguro para todos os possíveis circunstâncias, um método com o SuppressUnmanagedCodeSecurityAttribute atributo pode ser exposto a outros códigos gerenciados diretamente, tornando-o público em vez de particular. Se você optar por expor um método que tem o SuppressUnmanagedCodeSecurityAttribute atributo, a funcionalidade do código não gerenciado deve não ser somente seguros, mas também imunes ao ataque-se por chamadores mal-intencionados. Por exemplo, o código deve operar adequadamente mesmo quando não intencionais argumentos são gerados especificamente fazer com que o código de mau funcionamento.

Usando substituições declarativas e imperativas demandas

Declarações e outras substituições são mais rápidas quando declarativamente, enquanto as demandas são mais rápidas quando feitas imperativa. Embora os ganhos de desempenho não podem ser tão drásticas, usando declarativa substitui e as solicitações imperativas podem ajudá-lo a melhorar o desempenho do código.

Consulte também

Referência

File.GetCreationTime

SecurityPermission

SuppressUnmanagedCodeSecurityAttribute

Conceitos

Segurança de Acesso de código

Criação de bibliotecas de classe seguro