Erstellen einer benutzerdefinierten Verschlüsselungsberechtigung

* * *

Auf dieser Seite

Zielsetzung Zielsetzung
Betrifft Betrifft
Verwendung dieses Moduls Verwendung dieses Moduls
Zusammenfassung Zusammenfassung
Was Sie wissen sollten Was Sie wissen sollten
Erstellen der Klasse "EncryptionPermission" Erstellen der Klasse "EncryptionPermission"
Erstellen der Klasse "EncryptionPermissionAttribute" Erstellen der Klasse "EncryptionPermissionAttribute"
Installieren der Berechtigungsassembly im GAC Installieren der Berechtigungsassembly im GAC
Aktualisieren des von der DPAPI verwalteten Wrappercodes Aktualisieren des von der DPAPI verwalteten Wrappercodes
Aufrufen der DPAPI über eine Webanwendung mit mittlerer Vertrauenswürdigkeit Aufrufen der DPAPI über eine Webanwendung mit mittlerer Vertrauenswürdigkeit

Zielsetzung

Themenbereiche:

  • Entwickeln, Implementieren und Verwenden einer benutzerdefinierten CAS-Berechtigung.

  • Verwenden der benutzerdefinierten Codezugriffsberechtigung zur Steuerung des Zugriffs auf eine nicht verwaltete, von der DPAPI bereitgestellte Verschlüsselungsfunktionalität.

 

Betrifft

Die Informationen in diesem Modul gelten für folgende Produkte und Technologien:

  • Microsoft® Windows® 2000 Server und Windows 2000 Professional, Windows Server™ 2003, Windows XP Professional

  • Internet Information Server (IIS)

  • .NET Framework 1.1

 

Verwendung dieses Moduls

Empfehlungen für eine erfolgreiche Arbeit mit diesem Modul:

  • Sie sollten über Programmiererfahrung mit Visual C# .NET und Visual Studio .NET verfügen.

  • Lesen Sie "Erstellen einer DPAPI-Bibliothek". In diesem Modul wird gezeigt, wie eine verwaltete DPAPI-Wrapperassembly erstellt wird.

 

Zusammenfassung

Die CAS-Funktionen (Code Access Security) des .NET Framework sind erweiterbar. Dies ermöglicht die Implementierung eigener Berechtigungen zur Steuerung des Zugriffs auf wichtige, benutzerdefinierte Funktionen.

In diesem Modul wird beschrieben, wie Sie eine benutzerdefinierte CAS-Berechtigung erstellen, um den programmatischen Zugriff auf den Wrappercode der verwalteten Data Protection API (DPAPI) zu steuern. Der Code wird im Artikel "Erstellen einer DPAPI-Bibliothek" der MSDN-Bibliothek unter: https://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnntmag00/html/secure.asp beschrieben.

 

Was Sie wissen sollten

Die Berechtigungen der Codezugriffssicherheit müssen aus System.Security.CodeAccessPermission abgeleitet werden. Dadurch wird eine Implementierung der Demand-Methode bereitgestellt, die durch die IPermission-Schnittstelle definiert wird, zusammen mit den Methoden Assert, Deny und PermitOnly, die durch die IStackWalk-Schnittstelle definiert werden.

Codezugriffsberechtigungen (nicht Identitätsberechtigungen) implementieren auch die IUnrestrictedPermission-Schnittstelle, um anzuzeigen, dass die Berechtigung Teil des nicht eingeschränkten Berechtigungssatzes ist. Dadurch wird die Berechtigung automatisch für jeden Code gewährt, der vollständig vertrauenswürdig ist. Die Vererbungshierarchie der in diesem Modul implementierten benutzerdefinierten Klasse EncryptionPermission wird in Abbildung 1 dargestellt.

Vererbungshierarchie der benutzerdefinierten Klasse EncryptionPermission

Abbildung 1
Vererbungshierarchie der benutzerdefinierten Klasse EncryptionPermission

Die benutzerdefinierte Klasse EncryptionPermission behält den folgenden Status bei:

  • EncryptionPermissionFlag. Legt fest, ob durch Code, dem diese Berechtigung gewährt wurde, Daten verschlüsselt und/oder entschlüsselt werden können.

  • StorePermissionFlag. Bestimmt, ob durch Code, dem diese Berechtigung gewährt wurde, die DPAPI mit dem Computerspeicher und/oder dem Speicher des aktuellen Benutzers verwendet werden darf.

 

Erstellen der Klasse "EncryptionPermission"

Bei der Klasse EncryptionPermission handelt es sich um die benutzerdefinierte Berechtigungsimplementierung, die zur Autorisierung des Zugriffs auf die nicht verwaltete DPAPI-Funktionalität verwendet wird.

  • So erstellen Sie die Klasse CustomPermission

    1. Erstellen Sie mit dem Entwicklungsprogramm von Visual C#™ ein neues Klassenbibliotheksprojekt CustomPermission und benennen Sie class1.cs in EncryptionPermission.cs um.

    2. Fügen Sie der Assembly einen starken Namen hinzu, so dass Sie sie im GAC installieren können. Verwenden Sie das folgende Attribut in assemblyinfo.cs:

      [assembly: AssemblyKeyFile(@"..\..\CustomPermissions.snk")]
      
    3. Verwenden Sie eine feste Assemblyversion.

      [assembly: AssemblyVersion("1.0.0.1")]
      
    4. Fügen Sie folgende Anweisungen vom Typ using am Anfang von EncryptionPermission.cs ein.

      using System.Security;
      using System.Security.Permissions;
      
    5. Fügen Sie dem Namespace CustomPermissions die folgenden Aufzählungstypen hinzu.

      [Flags, Serializable]
      public enum EncryptionPermissionFlag
      {Encrypt = 0x01, Decrypt = 0x02}
      
      [Flags, Serializable]
      public enum StorePermissionFlag
      {User = 0x01, Machine = 0x02}
      
    6. Fügen Sie der EncryptionPermission-Klasse mit dem Attribut [Serializable] eine Serialisierungsunterstützung hinzu und leiten Sie diese aus CodeAccessSecurity und IUnrestrictedPermission ab. Deklarieren Sie außerdem die Klasse als "sealed", wie im folgenden Codebeispiel gezeigt.

      [Serializable]
      public sealed class EncryptionPermission : CodeAccessPermission, 
                                                IUnrestrictedPermission
      
    7. Fügen Sie zwei Variablen für private Mitglieder hinzu, um den Berechtigungsstatus aufrechtzuerhalten.

      private EncryptionPermissionFlag _permFlag;
      private StorePermissionFlag _storePermFlag;
      
    8. Ersetzen Sie den Standardkonstruktor durch die folgenden Konstruktoren.

      // Laut Konvention für Berechtigungstypen soll ein Konstruktor
      // die Aufzählung "PermissionState" akzeptieren.
      public EncryptionPermission(PermissionState state)
      {
        if (state.Equals(PermissionState.Unrestricted))
        {
          _permFlag = EncryptionPermissionFlag.Encrypt | 
                      EncryptionPermissionFlag.Decrypt;
          _storePermFlag = StorePermissionFlag.User | StorePermissionFlag.Machine;
        }
        else
        {
          _permFlag &= ~(EncryptionPermissionFlag.Encrypt | 
                        EncryptionPermissionFlag.Decrypt);
          _storePermFlag &= ~(StorePermissionFlag.User | 
                              StorePermissionFlag.Machine);
        }
      }
      // Dieser Konstruktor ermöglicht die Angabe der Verschlüsselungsart (Ver-
      // oder Entschlüsseln) über die Aufzählung "EncryptionPermissionFlag" und den DPAPI-
      // Schlüsselspeicher (Benutzer oder Computer), wie durch die Aufzählung
      // "StorePermissionFlag" festgelegt.
      public EncryptionPermission(EncryptionPermissionFlag cipher, 
                                  StorePermissionFlag store)
      {
        _permFlag = cipher;
        _storePermFlag = store;
      }
      public EncryptionPermission()
      {
        _permFlag &= ~EncryptionPermissionFlag.Encrypt | 
                      EncryptionPermissionFlag.Decrypt;
        _storePermFlag &= ~(StorePermissionFlag.User | StorePermissionFlag.Machine);
      }
      
    9. Fügen Sie folgende öffentliche Eigenschaften hinzu, damit der Status der Berechtigungsklasse von Kundenanwendungen festgelegt werden kann.

      // Wird diese Eigenschaft auf "true" gesetzt, ist Verschlüsselung zugelassen.
      public bool Encrypt
      {
        set {
          if(true == value)
          {
            _permFlag |= EncryptionPermissionFlag.Encrypt;
          }
          else
          {
            _permFlag &= ~EncryptionPermissionFlag.Encrypt;
          }
        }            
        get {
          return (_permFlag & EncryptionPermissionFlag.Encrypt).Equals(
                              EncryptionPermissionFlag.Encrypt);
        }
      }
      
      // Wird diese Eigenschaft auf "true" gesetzt, ist Entschlüsselung zugelassen.
      public bool Decrypt
      {
        set {
          if(true == value)
          {
            _permFlag |= EncryptionPermissionFlag.Decrypt;
          }
          else
          {
            _permFlag &= ~EncryptionPermissionFlag.Decrypt;
          }
        }
        get {
          return (_permFlag & EncryptionPermissionFlag.Decrypt).Equals(
                              EncryptionPermissionFlag.Decrypt);
        }
      }
      // Wird diese Eigenschaft auf "true" gesetzt, ist der DPAPI-Computerschlüssel zugelassen.
      public bool MachineStore
      {
        set {
          if(true == value)
          {
            _storePermFlag |= StorePermissionFlag.Machine;
          }
          else
          {
            _storePermFlag &= ~StorePermissionFlag.Machine;
          }
        }            
        get {
          return (_storePermFlag & StorePermissionFlag.Machine).Equals(
                                  StorePermissionFlag.Machine);
        }
      }
      // Wird diese Eigenschaft auf "true" gesetzt, ist der DPAPI-Benutzerschlüssel zugelassen.
      public bool UserStore
      {
        set {
          if(true == value)
          {
            _storePermFlag |= StorePermissionFlag.User;
          }
          else
          {
            _storePermFlag &= ~StorePermissionFlag.User;
          }
        }
        get {
          return (_storePermFlag & StorePermissionFlag.User).Equals(
                                  StorePermissionFlag.User);
        }
      }
      
    10. Implementieren Sie IPermission.Copy. Hierdurch wird eine identische Kopie der aktuellen Berechtigungsinstanz erstellt und an den Aufrufer zurückgegeben.

      public override IPermission Copy()
      {
        return  new EncryptionPermission(_permFlag, _storePermFlag);
      }
      
    11. Implementieren Sie IPermission.Intersect. Hierdurch wird ein Berechtigungsobjekt zurückgegeben, das aus der Schnittmenge zwischen der aktuellen Berechtigung und der bereitgestellten Berechtigung resultiert.

      public override IPermission Intersect(IPermission target)
      {
        // Die Eingabe von Null gibt eine Berechtigung ohne Status an.
        // Da es keinen allgemeinen Status gibt, wird Null von der Methode zurückgegeben.
        if (target == null)
          return null;
      
        if (!(target.GetType().Equals(this.GetType())))
          throw new ArgumentException(
                        "Argument muss vom Typ EncryptionPermission sein.");
      
        // Ziel einer "EncryptionPermission" zuordnen.
        EncryptionPermission targetPerm = (EncryptionPermission)target;
      
        EncryptionPermissionFlag intersectEncryption = this._permFlag & 
                                                      targetPerm._permFlag;
        StorePermissionFlag intersectStore = this._storePermFlag &
                                            targetPerm._storePermFlag;
      
        return new EncryptionPermission(intersectEncryption, intersectStore);
      }
      
    12. Implementieren Sie IPermission.Union. Hierdurch wird ein Berechtigungsobjekt zurückgegeben, das aus der Vereinigungsmenge zwischen der aktuellen Berechtigung und der bereitgestellten Berechtigung resultiert.

      public override IPermission Union(IPermission target)
      {
        if (target == null)
          return Copy();
      
        if (!(target.GetType().Equals(this.GetType())))
          throw new ArgumentException(
                            "Argument muss vom Typ EncryptionPermission sein.");
      
        // Ziel einer "EncryptionPermission" zuordnen.
        EncryptionPermission targetPerm = (EncryptionPermission)target;
      
        EncryptionPermissionFlag unionEncryption = this._permFlag | 
                                                  targetPerm._permFlag;
        StorePermissionFlag unionStore = this._storePermFlag | 
                                          targetPerm._storePermFlag;
      
        return new EncryptionPermission(unionEncryption, unionStore);
      }
      
    13. Implementieren Sie IPermission.IsSubsetOf. Durch diese Methode wird eine Boole'sche Variable zurückgegeben, die anzeigt, ob es sich bei der aktuellen Berechtigung um eine Teilmenge der bereitgestellten Berechtigung handelt. Damit dies der Fall ist, muss jedes Statuselement der aktuellen Berechtigung auch in der Zielberechtigung vorhanden sein.

      public override bool IsSubsetOf(IPermission target)
      {
        // Die Eingabe von Null gibt eine Berechtigung ohne Status an.
        // Die Berechtigung kann nur bei ähnlich leerem Status eine Teilmenge sein.
        bool canEncrypt, canDecrypt;
        bool canUseMachineStore, canUseUserStore;
      
        bool canTargetEncrypt, canTargetDecrypt;
        bool canTargetUseMachineStore, canTargetUseUserStore;
      
        canEncrypt = (this._permFlag & 
                      EncryptionPermissionFlag.Encrypt).
                      Equals(EncryptionPermissionFlag.Encrypt);
        canDecrypt = (this._permFlag & 
                      EncryptionPermissionFlag.Decrypt).
                      Equals(EncryptionPermissionFlag.Decrypt);
        canUseMachineStore = (this._storePermFlag & 
                              StorePermissionFlag.Machine).
                              Equals(StorePermissionFlag.Machine);
        canUseUserStore = (this._storePermFlag & 
                          StorePermissionFlag.User).
                          Equals(StorePermissionFlag.User);
      
        if (target == null)
        {
          if ((canEncrypt == false && canDecrypt == false) && (canUseMachineStore == 
              false  && canUseUserStore == false))
            return true;
          else
            return false;
        }
      
        if (!(target.GetType().Equals(this.GetType())))
          throw new ArgumentException(
                                "Argument muss vom Typ EncryptionPermission sein.");
      
        // Ziel einer "EncryptionPermission" zuordnen.
        EncryptionPermission targetPerm = (EncryptionPermission)target;
      
        canTargetEncrypt = (targetPerm._permFlag & 
                            EncryptionPermissionFlag.Encrypt).
                            Equals(EncryptionPermissionFlag.Encrypt);
        canTargetDecrypt = (targetPerm._permFlag &  
                            EncryptionPermissionFlag.Decrypt).
                            Equals(EncryptionPermissionFlag.Decrypt);
      
        canTargetUseMachineStore = (targetPerm._storePermFlag & 
                                    StorePermissionFlag.Machine).
                                    Equals(StorePermissionFlag.Machine);
        canTargetUseUserStore = (targetPerm._storePermFlag & 
                                StorePermissionFlag.User).
                                Equals(StorePermissionFlag.User);
      
        // Jede Wertesatz (true) dieser Berechtigung muss im Ziel existieren.
        // Durch folgenden Code wird überprüft, ob die aktuelle Berechtigung Teilmenge
        // des Ziels ist. Bei Abweichungen der aktuellen Berechtigung vom Ziel 
        // kann es sich nicht um eine Teilmenge handeln.
        if(canEncrypt == true && canTargetEncrypt == false)
          return false;
        if(canDecrypt == true && canTargetDecrypt == false)
          return false;
        if(canUseMachineStore == true && canTargetUseMachineStore == false)
          return false;
        if(canUseUserStore == true && canTargetUseUserStore == false)
          return false;
      
        return true;
      }
      
    14. Implementieren Sie ISecurityEncodable.ToXml und FromXml. Durch diese Methoden werden Instanzen eines Berechtigungsobjekts in ein XML-Format umgewandelt und umgekehrt. Diese Methoden werden zur Unterstützung der Serialisierung verwendet, zum Beispiel wenn das Sicherheitsattribut in Assemblymetadaten gespeichert wurde.

      public override SecurityElement ToXml()
      {
        // Erstellen eines neuen Elements. Der Name des Tags muss "Ipermission" sein.
        SecurityElement elem = new SecurityElement("IPermission");
      
        // Bestimmen des vollständig qualifizierten Typennamens (einschl. Assemblyname)
        // der Klasse "EncryptionPermission". (Der Name wird vom Sicherheitssystem
        // zum Suchen und Laden der Klasse verwendet.)
        string name = typeof(EncryptionPermission).AssemblyQualifiedName;
      
        // Hinzufügen von Attributen für Klassennamen und Protokollversion.
        // Derzeit muss die Version 1 sein.
        elem.AddAttribute("class", name);
        elem.AddAttribute("version", "1" );
      
        if (IsUnrestricted())
        {
          // Die Verwendung des Attributs "Unrestricted" ist konsistent mit den
          // integrierten Berechtigungstypen von .NET Framework und erleichtert
          // die kompakte Verschlüsselung.
          elem.AddAttribute("Unrestricted", Boolean.TrueString);
        }
        else
        {
          // Codieren jedes Statusfelds als Attribut des Elements "Permission".
          // Kompakt: Nur Statusparameter codieren, die nicht Standard sind.
          elem.AddAttribute("Flags", this._permFlag.ToString());
          elem.AddAttribute("Stores", this._storePermFlag.ToString());
        }
        // Rückgabe des fertig gestellten Elements.
        return elem;
      }
      
      // Konvertieren von "SecurityElement" (oder einer Elementstruktur) in eine
      // Berechtigungsinstanz.
      public override void FromXml(SecurityElement elem)
      {
        string attrVal = "";
        // Überprüfen auf nicht eingeschränkte Instanz.
        attrVal = elem.Attribute("Unrestricted");
        if (attrVal != null)
        {
          if(attrVal.ToLower().Equals("true"))
          { 
            this._permFlag = EncryptionPermissionFlag.Encrypt | 
                            EncryptionPermissionFlag.Decrypt;
            this._storePermFlag = StorePermissionFlag.Machine | 
                                  StorePermissionFlag.User;
          }
          return;
        }
      
        //Deaktivieren der Berechtigung und Speichern der Flags.
        this._permFlag &= ~(EncryptionPermissionFlag.Encrypt | 
                            EncryptionPermissionFlag.Decrypt);
        this._storePermFlag &= ~(StorePermissionFlag.Machine | 
                                StorePermissionFlag.User);
      
        attrVal = elem.Attribute("Flags");
        if (attrVal != null)
        {
          if(!attrVal.Trim().Equals(""))
          {
            this._permFlag = 
            (EncryptionPermissionFlag)Enum.Parse(typeof(EncryptionPermissionFlag),
                                                        attrVal);
          }
        }
      
        attrVal = elem.Attribute("Stores");
        if (attrVal != null)
        {
          if(!attrVal.Trim().Equals(""))
          {
            this._storePermFlag = 
                        (StorePermissionFlag)Enum.Parse(typeof(StorePermissionFlag), 
                                                              attrVal);
          }
        }
      }
      
    15. Implementieren Sie IUnrestrictedPermission.IsUnrestricted. Durch diese Methode wird true zurückgegeben, wenn sich die Berechtigungsinstanz in einem nicht eingeschränkten Status befindet. In diesem Fall ermöglicht die nicht eingeschränkte Instanz EncryptionPermission, dass Daten durch Code ver- und entschlüsselt werden, wobei sie sowohl den DPAPI-Computerspeicher als auch den Benutzerspeicher verwendet.

      public bool IsUnrestricted()
      {
        bool canEncrypt, canDecrypt, canUseUserStore, canUseMachineStore;
        canEncrypt = (this._permFlag & 
                      EncryptionPermissionFlag.Encrypt).
                      Equals(EncryptionPermissionFlag.Encrypt);
        canDecrypt = (this._permFlag & 
                      EncryptionPermissionFlag.Decrypt).
                      Equals(EncryptionPermissionFlag.Decrypt);
        canUseUserStore = (this._storePermFlag & 
                          StorePermissionFlag.User).
                          Equals(StorePermissionFlag.User);
        canUseMachineStore = (this._storePermFlag & 
                              StorePermissionFlag.Machine).
                              Equals(StorePermissionFlag.Machine);
        return ((canEncrypt && canDecrypt) && 
                (canUseUserStore && canUseMachineStore));
      }
      

 

Erstellen der Klasse "EncryptionPermissionAttribute"

Im .NET Framework werden Attributklassen verwendet, die zum Verschlüsseln von Berechtigungsinstanzen den jeweiligen Partnerberechtigungsklassen zugeordnet sind. Berechtigungsattribute werden zur Unterstützung von deklarativer Sicherheitssyntax benötigt.

  • So erstellen Sie die Klasse "EncryptionPermissionAttribute"

    1. Fügen Sie dem aktuellen Projekt eine neue Klassendatei hinzu, EncryptionPermissionAttribute.cs.

    2. Fügen Sie folgende Anweisungen vom Typ using am Anfang der neuen Datei ein.

      using System.Security;
      using System.Diagnostics;
      using System.Security.Permissions;
      
    3. Leiten Sie die Attributklasse aus CodeAccessSecurityAttribute ab und kapseln Sie diese.

      public sealed class EncryptionPermissionAttribute : 
                                   CodeAccessSecurityAttribute
      
    1. Fügen Sie der Klasse Serialisierungsunterstützung hinzu und nutzen Sie das Attribut AttributeUsage, um festzulegen, an welcher Stelle das Attribut für benutzerdefinierte Berechtigungen verwendet werden darf.

      [Serializable, 
      AttributeUsage(AttributeTargets.Method |      // Verwendung mit Methoden
                    AttributeTargets.Constructor | // Verwendung mit Konstruktoren
                    AttributeTargets.Class |       // Verwendung mit Klassen
                    AttributeTargets.Struct |      // Verwendung mit Strukturen
                    AttributeTargets.Assembly,     // Verwendung auf Assemblyebene
                    AllowMultiple = true,          // Verwendung mit multiplen Attributen 
                                                    // Instanzen pro Programmelement 
                                                    // (Klasse, Methode und so weiter)
                    Inherited = false)]            // Kann nicht vererbt werden
      
    2. Fügen Sie der Klasse Variablen für private Benutzer hinzu, um den von der zugeordneten Berechtigungsklasse erhaltenen Status zu spiegeln.

      // Die folgenden Statusfelder spiegeln die im zugeordneten
      // Berechtigungstyp verwendeten.
      private bool _encrypt = false;
      private bool _decrypt = false;
      private bool _machineStore = false;
      private bool _userStore = false;
      
    3. Ersetzen Sie den Standardkonstruktor durch den folgenden Konstruktor.

      // Rückgabe des Aktionscodes an die Basisklasse.
      public EncryptionPermissionAttribute(SecurityAction action) : base(action)
      {
      }
      
    4. Fügen Sie folgende öffentliche Eigenschaften hinzu, um die Eigenschaften der zugeordneten Berechtigungsklasse zu spiegeln.

      public bool Encrypt
      {
        get {
          return _encrypt;
        }
        set {
          _encrypt = value;
        }
      }
      public bool Decrypt
      {
        get {
          return _decrypt;
        }
        set {
          _decrypt = value;
        }
      }
      public bool UserStore
      {
        get {
          return _userStore;
        }
        set {
          _userStore = value;
        }
      }
      public bool MachineStore
      {
        get {
          return _machineStore;
        }
        set {
          _machineStore = value;
        }
      }
      
    5. Implementieren Sie SecurityPermissionAttribute.CreatePermission. Durch diese Methode wird ein Berechtigungsobjekt erstellt, das dann serialisiert und mit der angegebenen Auflistung SecurityAction in den Metadaten einer Assembly beibehalten werden kann.

      public override IPermission CreatePermission()
      {
        // Durch die Laufzeit wird automatisch eine Eigenschaft erstellt,
        // die anzeigt, ob eine nicht eingeschränkte Instanz benötigt wird.
        if((Unrestricted) || ((_encrypt && _decrypt) && 
                              (_userStore && _machineStore)))
        {
          return new EncryptionPermission(PermissionState.Unrestricted);
        }
      
        // Kopieren des Status vom Attribut auf das Berechtigungsobjekt
        EncryptionPermissionFlag cipher = 0x0;
        StorePermissionFlag store = 0x0;
      
        if(_encrypt)
          cipher |= EncryptionPermissionFlag.Encrypt;
      
        if(_decrypt)
          cipher |= EncryptionPermissionFlag.Decrypt;
      
        if(_userStore)
          store |= StorePermissionFlag.User;
      
        if(_machineStore)
          store |= StorePermissionFlag.Machine;
      
        // Rückgabe der letzten Berechtigung.
        return new EncryptionPermission(cipher, store);
      }
      
    6. Erstellen Sie die Lösung.

 

Installieren der Berechtigungsassembly im GAC

Jede Assembly, die eine benutzerdefinierte Sicherheitsberechtigung implementiert, muss vollständig vertrauenswürdig sein. In der Praxis bedeutet das, dass die Assembly auf dem Computer installiert werden muss, auf dem sie verwendet wird. Durch die standardmäßige Sicherheitsrichtlinie wird dann die vollständige Vertrauenswürdigkeit zugeordnet. Code innerhalb von My_Computer_Zone wird durch die Standardrichtlinie als vollständig vertrauenswürdig gekennzeichnet.

Die Installation einer Assembly im GAC ist eine Möglichkeit, durch die Richtlinie die volle Vertrauenswürdigkeit für Codezugriffssicherheit zu garantieren. Die GAC ist ein geeigneter Speicherort für die Berechtigungsassembly, da die Assembly sowohl von der Richtlinie für Codezugriffssicherheit auf dem lokalen Computer verwendet wird als auch für alle .NET Framework-Anwendungen verfügbar ist, die auf dem lokalen Computer installiert sind.

Führen Sie den folgenden Befehl aus, um die benutzerdefinierte Berechtigungsassembly im GAC des lokalen Computers zu installieren.

gacutil.exe /i custompermission.dll

Aktualisieren des von der DPAPI verwalteten Wrappercodes

Die DPAPI-Funktionalität wird derzeit durch die Klassenbibliothek des .NET Framework nicht direkt unterstützt. Um DPAPI von einer .NET Framework-Anwendung aus aufzurufen, muss P/Invoke verwendet werden. Codebeispiel zum Erstellen einer verwalteten DPAPI-Wrapperassembly finden Sie unter "Erstellen einer DPAPI-Bibliothek".

Ohne weitere Änderungen kann der verwaltete DPAPI-Wrapper in dem genannten Artikel nur von vollständig vertrauenswürdigem Code aufgerufen werden. Damit der DPAPI-Wrapper auch von teilweise vertrauenswürdigem Code aufgerufen werden kann, wie von einer ASP.NET-Webanwendung mit mittlerer Vertrauenswürdigkeit, müssen die Aufrufe an nicht verwaltete DPAPI-Funktionen in einer Sandbox ausgeführt werden. Nehmen Sie hierzu folgende Änderungen vor:

  • Weisen Sie die Berechtigung für nicht verwalteten Code im DPAPI-Wrappercode zu. Für jeden aufrufenden Code wird dann die Berechtigung für nicht verwalteten Code nicht mehr benötigt.

  • Autorisieren Sie den aufrufenden Code im Wrapper durch Anfordern der benutzerdefinierten EncryptionPermission. Der Aufruf Demand tritt, in Übereinstimmung mit dem entsprechenden Verwendungsmuster, vor dem Aufruf Assert auf. Weitere Informationen zur sicheren Verwendung von Assert finden Sie unter "Assert und RevertAssert" in Module 8, "Codezugriffssicherheit in der Praxis".

  • So ändern Sie den von der DPAPI verwalteten Wrapper

    1. Erstellen Sie den von der DPAPI verwalteten Wrapper wie in "Erstellen einer DPAPI-Bibliothek" beschrieben.

    2. Fügen Sie einen Verweis auf die Assembly CustomPermission hinzu.

    3. Öffnen Sie dataprotection.cs von der verwalteten Wrapper-Bibliothek aus und fügen Sie am Anfang der Datei die folgenden Anweisungen vom Typ using unterhalb der entsprechenden bestehenden Anweisungen hinzu.

      using System.Security;
      using System.Security.Permissions;
      using CustomPermissions;
      
    4. Suchen Sie die Methode Encrypt in dataprotection.cs und fügen Sie folgenden Code am Anfang des äußeren Blocks try in der Methode Encrypt hinzu.

      // Festlegen von storeFlag je nach der Art, wie der Aufrufende
      // den verwalteten DPAPI-Wrapper verwendet. 
      StorePermissionFlag storeFlag;
      if(Store.USE_MACHINE_STORE == store)
      {
        storeFlag = StorePermissionFlag.Machine;
      }
      else
      {
        storeFlag = StorePermissionFlag.User;
      }
      // Anfordern der benutzerdefinierten EncryptionPermission.
      (new EncryptionPermission(EncryptionPermissionFlag.Encrypt, storeFlag)).
                                                                    Demand();
      
      // Zuordnen der Berechtigung für nicht verwalteten Code.
      (new SecurityPermission(SecurityPermissionFlag.UnmanagedCode)).Assert();
      // Mit P/Invoke jetzt nicht verwaltete DPAPI-Funktionen aufrufen.
      
    5. Fügen Sie den folgenden Block finally dem äußeren Block try in der Methode Encrypt hinzu.

      finally
      {
        CodeAccessPermission.RevertAssert();
      }
      
    6. Suchen Sie die Methode Decrypt in dataprotection.cs und fügen Sie folgenden Code am Anfang des äußeren Blocks try hinzu.

      StorePermissionFlag storeFlag;
      if(Store.USE_MACHINE_STORE == store)
      {
        storeFlag = StorePermissionFlag.Machine;
      }
      else
      {
        storeFlag = StorePermissionFlag.User;
      }  
        // Anfordern der benutzerdefinierten EncryptionPermission.
        (new EncryptionPermission(EncryptionPermissionFlag.Decrypt, storeFlag)).
                                                                    Demand();
        // Zuordnen der Berechtigung für nicht verwalteten Code.
        (new SecurityPermission(SecurityPermissionFlag.UnmanagedCode)).Assert();
      
    7. Fügen Sie den folgenden Block finally dem äußeren Block try in der Methode Decrypt hinzu.

      finally
      {
        CodeAccessPermission.RevertAssert();
      }

 

Aufrufen der DPAPI über eine Webanwendung mit mittlerer Vertrauenswürdigkeit

Damit der von der DPAPI verwaltete Wrapper über eine Webanwendung mit mittlerer Vertrauenswürdigkeit oder über Code mit mittlerer Vertrauenswürdigkeit aufgerufen werden kann, muss die Richtlinie für Codezugriffssicherheit so konfiguriert werden, dass der Code die benutzerdefinierte EncryptionPermission erhält.

Mit diesem Schritt erstellen Sie eine Webanwendung für Testzwecke und ändern die Richtlinie für Codezugriffssicherheit von ASP.NET für eine Webanwendung mit mittlerer Vertrauenswürdigkeit, um diese der EncryptionPermission zu gewähren.

  • So erstellen Sie eine Webanwendung für Testzwecke

    1. Fügen Sie der aktuellen Lösung eine C#-ASP.NET-Webanwendung hinzu.

    2. Fügen Sie einen Verweis auf die Assembly Dataprotection.dll hinzu.

    3. Fügen Sie folgende Felder zu Webform1.aspx hinzu.

      • Ein Eingabefeld für die zu verschlüsselnden Daten. Verwenden Sie die ID txtDataToEncrypt.

      • Ein Feld für die verschlüsselten Daten. Verwenden Sie die ID txtEncryptedData.

      • Ein Feld für die entschlüsselten Daten. Verwenden Sie die ID txtDecryptedData.

      • Eine Schaltfläche Verschlüsseln. Verwenden Sie die ID btnEncrypt.

      • Eine Schaltfläche Entschlüsseln. Verwenden Sie die ID btnDecrypt.

      • Eine Bezeichnung für eine Fehlermeldung. Verwenden Sie die ID lblError.

    4. Fügen Sie folgende Anweisung vom Typ using am Anfang von WebForm1.aspx.cs unterhalb der entsprechenden, bereits bestehenden Anweisungen ein.

      using DataProtection;
      
    5. Fügen Sie folgenden Code für den Ereignishandler bei gedrückter Schaltfläche Verschlüsseln ein.

      private void btnEncrypt_Click(object sender, System.EventArgs e)
      {
        DataProtector dp = new DataProtector(
                                    DataProtector.Store.USE_MACHINE_STORE );
        try
        {
          byte[] dataToEncrypt = Encoding.ASCII.GetBytes(txtDataToEncrypt.Text);
          // Wird in diesem Beispiel keine optionale Entropie übergeben,
          // könnte zur Sicherheit ein (von der Anwendung gespeicherter) Zufallswert
          // übergeben werden, wenn DPAPI mit Computerspeicher verwendet wird.
          txtEncryptedData.Text =
                  Convert.ToBase64String(dp.Encrypt(dataToEncrypt,null));
        }
        catch(Exception ex)
        {
          lblError.ForeColor = Color.Red;
          lblError.Text = "Exception.<br>" + ex.Message;
          return;
        }
        lblError.Text = "";
      }
      
    6. Fügen Sie folgenden Code für den Ereignishandler bei gedrückter Schaltfläche Entschlüsseln ein.

      private void btnDecrypt_Click(object sender, System.EventArgs e)
      {
        DataProtector dp = new DataProtector(DataProtector.Store.USE_MACHINE_STORE);
        try
        {
          byte[] dataToDecrypt = Convert.FromBase64String(txtEncryptedData.Text);
          // Der optionale Entropieparameter ist Null. 
          // Bei Verwendung von Entropie in der Verschlüsselungsmethode muss
          // hier der gleiche Entropieparameter eingefügt werden.
          txtDecryptedData.Text = 
              Encoding.ASCII.GetString(dp.Decrypt(dataToDecrypt,null));
        }
        catch(Exception ex)
        {
          lblError.ForeColor = Color.Red;
          lblError.Text = "Exception.<br>" + ex.Message;
          return;
        }
        lblError.Text = "";
      }
      
    7. Konfigurieren Sie die Webanwendung für mittlere Vertrauenswürdigkeit, indem Sie das folgende Element der Datei Web.config der Anwendung im Abschnitt <system.web> hinzufügen.

      <trust level="Medium" />
      
    8. Erstellen Sie die Lösung.

  • So ändern Sie die Richtlinie für mittlere Vertrauenswürdigkeit

    1. Öffnen Sie die Richtliniendatei für mittlere Vertrauenswürdigkeit mit Visual Studio® .NET oder mit einem Texteditor. Die Richtliniendatei befindet sich an folgendem Speicherort.

      %windir%\Microsoft.NET\Framework\{version}\CONFIG\web_mediumtrust.config
      
    2. Legen Sie die EncryptionPermission fest, indem Sie das folgende Element <SecurityClass> dem Element <SecurityClasses> hinzufügen.

      <SecurityClass Name="EncryptionPermission" 
             Description="CustomPermission.EncryptionPermission, 
                          CustomPermission, Version=1.0.0.1, 
                          Culture=neutral, 
                          PublicKeyToken=951cd7d57a536a94"/>
      

      Legen Sie den Attributwert PublicKeyToken auf das entsprechende Token für den öffentlichen Schlüssel Ihrer Assembly fest. Verwenden Sie den folgenden Befehl, um das Token für den öffentlichen Schlüssel für die benutzerdefinierte Berechtigungsassembly zu extrahieren.

      sn -T custompermission.dll
      

      Hinweis: Verwenden Sie den Schalter -T als Großbuchstaben.

    3. Suchen Sie den Berechtigungssatz mit der Bezeichnung ASP.NET in der Richtliniendatei für mittlere Vertrauenswürdigkeit und fügen Sie folgende Berechtigungselemente hinzu.

      <IPermission class="EncryptionPermission" 
           version="1" Flags="Encrypt,Decrypt" 
           Stores="Machine,User">
      </IPermission>
      

      Diese Berechtigung ordnet Webanwendungen mit mittlerer Vertrauenswürdigkeit eine nicht eingeschränkte EncryptionPermission zu, indem sie dem Code das Ver- und Entschlüsseln von Daten erlaubt. Sowohl DPAPI-Computer- als auch Benutzerspeicher kann verwendet werden. Im oben dargestellten Element wird die unterstützte Syntax aufgezeigt. Sie entspricht dem Folgenden:

      <IPermission class="EncryptionPermission" 
           version="1" Unrestricted="true" >
      </IPermission>
      

      Sie können dem Code eine eingeschränkte Berechtigung zuordnen, indem Sie nur die relevanten Attribute verwenden. Um den Code zum Beispiel auf das Entschlüsseln von Daten unter Verwendung des Computerschlüssels im Computerspeicher zu beschränken, verwenden Sie das folgende Element.

      <IPermission class="EncryptionPermission" 
           version="1" Flags="Decrypt" 
           Stores="Machine">
      </IPermission>
      
    4. Speichern Sie die Richtliniendatei.

      Nun können Sie die Webanwendung für Testzwecke ausführen und überprüfen, ob Sie Daten mit der DPAPI von einer teilweise vertrauenswürdigen Webanwendung aus ver- und entschlüsseln können.

Weitere Informationen zum Ausführen von privilegiertem Code in einer Sandbox und zur Arbeit mit der Richtlinie für Codezugriffssicherheit von ASP.NET finden Sie in Modul 9, "Verwenden der Codezugriffssicherheit mit ASP.NET."