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:
- Pfad (URL) des Codes
- Name der zu erzeugenden Code Group
- 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.