Freigeben über


Sicherheitsoptimierungen

Aktualisiert: November 2007

Sicherheitsüberprüfungen können bei einigen Anwendungen Leistungsprobleme verursachen. Es gibt zwei Optimierungstechniken, die Sie zur Leistungsverbesserung verwenden können. In einem Verfahren werden Sicherheitsforderungen kombiniert, und in dem anderen werden Forderungen von Berechtigungen zum Aufrufen von nicht verwaltetem Code unterdrückt. Diese Techniken steigern zwar möglicherweise die Leistung der Anwendung, jedoch können dadurch bei der Anwendung Sicherheitslücken entstehen, die sich für Angriffe ausnutzen lassen. Vor dem Anwenden dieser Optimierungstechniken müssen Sie daher folgende Sicherheitsvorkehrungen treffen:

  • Befolgen Sie die Richtlinien für verwalteten Code in Richtlinien für das Schreiben von sicherem Code.

  • Sie müssen die Auswirkungen der Optimierungstechniken auf die Sicherheit verstanden haben und ggf. andere Methoden zum Schutz der Anwendung verwenden.

  • Implementieren Sie das Minimum an Sicherheitsoptimierungen, das zum Verbessern der Anwendungsleistung erforderlich ist.

Nach der Optimierung des Codes müssen Sie den optimierten Code testen und ermitteln, ob sich die Leistung tatsächlich verbessert hat. Wenn dies nicht der Fall ist, sollten Sie die Sicherheitsoptimierungen entfernen, um versehentliche Sicherheitslücken zu vermeiden.

Vorsicht:

Für die Sicherheitsoptimierung müssen Sie die standardmäßig vorgegebene Codezugriffssicherheit ändern. Vergewissern Sie sich vor dem Einsatz der Optimierungstechniken, dass Sie deren Auswirkungen auf die Sicherheit verstehen, damit keine Sicherheitsrisiken in den Code eingeführt werden.

Kombinieren von Sicherheitsforderungen

Zum Optimieren von Code, der Sicherheitsforderungen vornimmt, können Sie in einigen Fällen ein Verfahren zum Kombinieren von Forderungen anwenden.

Wenn z. B. Folgendes gegeben ist:

  • Der Code führt eine Reihe von Operationen in einer einzigen Methode aus, und:

  • Beim Ausführen der einzelnen Operationen ruft der Code eine verwaltete Klassenbibliothek auf, die fordert, dass der Code für jeden Aufruf der Bibliothek über dieselbe Berechtigung verfügt.

In diesem Falle gilt Folgendes:

  • Sie können den Code so ändern, dass er Demand und Assert der betreffenden Berechtigung ausführt, um den Aufwand durch die Sicherheitsforderungen herabzusetzen.

Wenn dem Aufruf der Methode eine lange Aufrufliste vorausgeht, kann dieses Verfahren die Leistung erheblich verbessern.

Nehmen Sie zur Veranschaulichung einmal an, Methode M führt 100 Operationen durch. Jede Operation ruft eine Bibliothek auf, die eine Sicherheitsforderung vornimmt. Diese fordert, dass der Code und alle seine Aufrufer die Berechtigung X haben müssen. Aufgrund der Sicherheitsforderungen bewirkt jede Operation, dass die Laufzeit die gesamte Aufrufliste durchläuft und die Berechtigungen der einzelnen Aufrufer untersucht, um zu bestimmen, ob jedem Aufrufer tatsächlich die Berechtigung X erteilt wurde. Wenn die Aufrufliste über Methode M Ebenen tief ist, sind 100n Vergleiche erforderlich.

Zur Optimierung können Sie in Methode M Folgendes ausführen:

  • Fordern Sie X, die die Durchführung eines Stackwalks (Tiefe n) durch die Laufzeit bewirkt. Dies gewährleistet, dass alle Aufrufer über Berechtigung X verfügen.

  • Fordern Sie anschließend Berechtigung X mit Assert an, wodurch nachfolgende Stackwalks bei Methode M beendet und erfolgreich abgeschlossen werden. Dies setzt die Anzahl der Berechtigungsvergleiche um 99n herab.

Im folgenden Beispiel nimmt die GetFileCreationTime-Methode eine Zeichenfolgenentsprechung eines Verzeichnisses als Parameter an und zeigt den Namen und das Erstellungsdatum sämtlicher Dateien in diesem Verzeichnis an. Die statische File.GetCreationTime-Methode liest Informationen aus den Dateien, benötigt jedoch für jede gelesene Datei eine Forderung und einen Stackwalk. Diese Methode erstellt eine neue Instanz des FileIOPermission-Objekts, führt eine Forderung zum Überprüfen der Berechtigungen sämtlicher Aufrufer im Stapel aus und fordert die Berechtigung anschließend mit Assert an, wenn die Forderung erfolgreich war. Nach Abschluss der Forderung wird nur ein Stackwalk durchgeführt, und die Methode liest die Erstellungszeit aus jeder Datei im übergebenen Verzeichnis.

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

Nach Abschluss der Forderung im vorigen Beispiel werden sämtliche Dateien mit dem jeweiligen Erstellungsdatum und der jeweiligen Erstellungszeit für das übergebene Verzeichnis angezeigt. Wenn die Forderung fehlschlägt, wird die Sicherheitsausnahme abgefangen, und die folgende Meldung wird auf der Konsole angezeigt:

You do not have permission to read this directory.

Unterdrücken von Forderungen von Berechtigungen für nicht verwalteten Code

Für Code, der die Berechtigung zum Aufrufen von nicht verwaltetem Code hat, steht ein spezielles Optimierungsverfahren zur Verfügung. Dieses ermöglicht es verwaltetem Code, nicht verwalteten Code ohne den Mehraufwand eines Stackwalks aufzurufen. Die Assertion von Berechtigungen für nicht verwalteten Code können den Stackwalk verkürzen, durch das hier beschriebene Verfahren kann sie jedoch vollständig entfallen. (Weitere Informationen über die Berechtigung zum Aufrufen von nicht verwaltetem Code finden Sie im Abschnitt SecurityPermission.)

In der Regel löst ein Aufruf von nicht verwaltetem Code eine Forderung einer Berechtigung für nicht verwalteten Code aus, die zu einem Stackwalk führt, bei dem bestimmt wird, ob alle Aufrufer über die Berechtigung zum Aufrufen von nicht verwaltetem Code verfügen. Durch Anwenden des benutzerdefinierten Attributs SuppressUnmanagedCodeSecurityAttribute auf die Methode, die den nicht verwalteten Code aufruft, wird die Forderung unterdrückt. Dieses Attribut ersetzt den vollständigen Stackwalk zur Laufzeit durch eine Überprüfung, bei der lediglich die Berechtigungen des direkten Aufrufers zum Zeitpunkt der Verknüpfung überprüft werden. Tatsächlich öffnet die Verwendung dieses Attributs den Zugang zu nicht verwaltetem Code. Nur Code mit der Berechtigung für nicht verwalteten Code kann dieses Attribut verwenden, andernfalls bleibt die Anwendung wirkungslos.

Vorsicht:

Das SuppressUnmanagedCodeSecurityAttribute-Attribut sollte nur äußerst vorsichtig verwendet werden. Die falsche Verwendung dieses Attributs kann zu Sicherheitsrisiken führen. Das SuppressUnmanagedCodeSecurityAttribute-Attribut darf keinesfalls verwendet werden, um wenig vertrauenswürdigem Code, d. h. Code ohne die Berechtigung für nicht verwalteten Code, den Aufruf von nicht verwaltetem Code zu ermöglichen.

Es empfiehlt sich, dieses Attribut lediglich auf privat deklarierte Einstiegspunkte in nicht verwaltetem Code anzuwenden, sodass Code in anderen Assemblys keinen Zugriff hat und die Vorteile der Sicherheitsunterdrückung nicht ausnutzen kann. Normalerweise fordert der hoch vertrauenswürdige verwaltete Code, der dieses Attribut verwendet, zunächst eine Berechtigung von den Aufrufern, bevor der nicht verwaltete Code im Namen des Aufrufers aufgerufen wird.

Das folgende Beispiel veranschaulicht die Anwendung des SuppressUnmanagedCodeSecurityAttribute-Attributs auf einen privaten Einstiegspunkt.

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

Wenn der seltene Umstand vorliegt, dass nicht verwalteter Code in allen möglichen Situationen vollständig sicher ist, kann eine Methode mit dem SuppressUnmanagedCodeSecurityAttribute-Attribut für anderen verwalteten Code direkt verfügbar gemacht werden, indem dieser statt als privat als öffentlich definiert wird. Wenn Sie eine Methode mit dem SuppressUnmanagedCodeSecurityAttribute-Attribut verfügbar machen, muss die Funktionalität des nicht verwalteten Codes nicht nur sicher sein, sie darf darüber hinaus auch nicht gegen Angriffe durch bösartige Aufrufer anfällig sein. Der Code muss beispielsweise auch dann ordnungsgemäß funktionieren, wenn unerwünschte Argumente mit dem Ziel einer fehlerhaften Ausführung des Codes erstellt werden.

Verwenden von deklarativen Überschreibungen und imperativen Forderungen

Assertionen und andere Überschreibungen sind am schnellsten, wenn sie deklarativ erfolgen, während Forderungen am schnellsten sind, wenn sie imperativ erfolgen. Obwohl die Leistungssteigerung möglicherweise unwesentlich ist, können deklarative Überschreibungen und imperative Forderungen die Ausführung des Codes beschleunigen.

Siehe auch

Konzepte

Erstellen von sicheren Klassenbibliotheken

Referenz

File.GetCreationTime

SecurityPermission

SuppressUnmanagedCodeSecurityAttribute

Weitere Ressourcen

Codezugriffssicherheit