Code Access Security (CAS) programmatisch angewandt (Teil 1)

Anders als unter Windows, wo ja bekanntlich die Rechte auf Benutzerbasis festgelegt werden, können unter .NET Rechte für (managed) Code definiert werden. Was heißt das? Unabhängig vom Benutzer läuft ein bestimmter .NET Code nur mit den Rechten, die der Admin definiert. Dabei gilt: nichts definiert – keine Rechte (bzw. nur Basis-Rechte; Abhängig von der Herkunft fällt der Code in bestimmte Security-Zonen, wie z.B. MyComputer, LocalIntranet bzw. Internet). CAS basiert auf Beweisen, wobei dies z.B. eine URL oder ein UNC-Pfad sein kann oder aber auch ein Hash, ein Strong Name bzw. eine Digitale Signatur. Der Pfad bzw. die URL ist dabei die schwächste Sicherheitsstufe, wird doch dem Code, welcher dort liegt, vertraut – egal wie der aussieht. Wenn der Server vom Admin sicher verwaltet wird, ist das auch kein Problem, besser ist es aber, auf einen Strong Name oder ein Zertifikat zu setzen.

 

Da ich immer wieder danach gefragt werde, werde ich hier einmal aufzeigen, wie dies programmatisch erledigt wird.

 

Beispiel 1: Basierend auf einer URL

 

Dazu bauen wir uns eine Prozedur, welche folgende Parameter hat:

  1. Pfad (URL) des Codes
  2. Name der zu erzeugenden Code Group
  3. Beschreibung der zu erzeugenden Code Group

 

  Private Sub CreatePolicy(ByVal sCodePath As String, ByVal sName As String, ByVal sDescription As String)

Zuerst einmal brauchen wir eine Referenz auf das jeweilige Root Level (im Beispiel: User).

 

    Dim PolLevel As PolicyLevel

    Dim PolLevels As IEnumerator = SecurityManager.PolicyHierarchy

    Do While PolLevels.MoveNext

      PolLevel = DirectCast(PolLevels.Current, PolicyLevel)

      If PolLevel.Label = "User" Then

        Exit Do

      End If

    Loop

Nun benötigen wir eine Referenz auf die All_Code Group des ausgewählten Root Levels:

 

    Dim AllCodeGroup As UnionCodeGroup = DirectCast(PolLevel.RootCodeGroup, UnionCodeGroup)

Wollen wir spezifische Rechte einrichten, so müssen wir mit Permissions arbeiten. Hier im Beispiel wurden FileIOPermissions verwendet. Der System.Security.Permissions Namespace hält noch viele weitere bereit.

    Dim FileReadPermission As FileIOPermission = New FileIOPermission(FileIOPermissionAccess.Read, "C:\Test.ini")

Nun wird ein PermissionSet angelegt, welche alle erzeugten Permissions halten wird und die einzelnen Permissions werden hinzugefügt:

 

    Dim permSet As PermissionSet = New PermissionSet(PermissionState.None)

    permSet.AddPermission(FileReadPermission)

Soll – z.B. für VSTO Assemblies – Full Trust eingestellt werden, kann man sich sog. Named PermissionSets bedienen:

'Dim permSet As PermissionSet = PolLevel.GetNamedPermissionSet("FullTrust")

Da wir Rechte auf Basis einer URL vergeben wollen, benötigen wir eine URLMembershipCondition für den übergebenen Code-Pfad (URL):

    Dim URLMemCond As UrlMembershipCondition = New UrlMembershipCondition(sCodePath)

Jetzt müssen wir noch eine neue Code Group erstellen mit Name und Beschreibung und diese der All_Code Group hinzufügen:

 

    Dim NewCodeGroup As UnionCodeGroup = New UnionCodeGroup(URLMemCond, New PolicyStatement(permSet))

    NewCodeGroup.Name = sName

    NewCodeGroup.Description = sDescription

    AllCodeGroup.AddChild(NewCodeGroup)

Das Wichtigste zu Schluß: die erzeugte Policy speichern:

    SecurityManager.SavePolicy()

  End Sub

Weil ich in dem Beispiel nicht alle Objekte voll qualifiziert habe, müssen wir zu Beginn noch die verwendeten Namespaces importieren:

Imports System.Security.Policy

Imports System.Security.Permissions

 

 

Das Äquivalent dazu zum Entfernen der erzeugten Policy schaut dann so aus:

 

 

  Private Sub RemovePolicy(ByVal sLevel As String, ByVal sName As String)

    Dim PolLevel As PolicyLevel

    Dim PolLevels As IEnumerator = SecurityManager.PolicyHierarchy

    Do While PolLevels.MoveNext

      PolLevel = DirectCast(PolLevels.Current, PolicyLevel)

      If PolLevel.Label = sLevel Then

        Exit Do

      End If

    Loop

    Dim AllCodeGroup As UnionCodeGroup = DirectCast(PolLevel.RootCodeGroup, UnionCodeGroup)

    Dim AvailableCodeGroups As IEnumerator = AllCodeGroup.Children.GetEnumerator()

    Dim ActCodeGroup As CodeGroup

    Do While AvailableCodeGroups.MoveNext

      ActCodeGroup = DirectCast(AvailableCodeGroups.Current(), CodeGroup)

      If ActCodeGroup.Name = sName Then

        AllCodeGroup.RemoveChild(ActCodeGroup)

        SecurityManager.SavePolicy()

        Exit Do

      End If

    Loop

  End Sub

Um Policies anzulegen bzw. zu entfernen, benötigen wir Admin-Rechte. Diese Vorgehensweise ist also in managed Networks verwendbar, wenn der Code mit erhöhten Rechten laufen kann (der Benutzer hat nur eingeschränkte Rechte, aber der Admin gibt dem Code sog. Elevated Priviledges).

Wie dieser Code per Windows Installer über eine Installer-Klasse verwendet wir, zeige ich in einer der nächsten Folgen.

 

Die nächste Folge beschäftigt sich mit dem Einrichten eines Trusted Publishers auf Basis eines Strong Names.