CAS im .NET Framework

Auswirkungen der Code Access Security auf das Setup einer Anwendung
Kommentare

In den Unternehmensnetzwerken werden Anwendungen gerne zentral auf einem Server abgelegt, sodass die Anwender diese Programme über ein Netzlaufwerk starten können. Was seit Jahren bewährte Praxis war, wird bei einer .NET-Anwendung mit der Standardinstallation des .NET Framework zu einem gewissen Problem, auf das der Entwickler in seinem Installationsprogramm der Anwendung reagieren muss.

Angesichts der „Folterwerkzeuge“, die im .NET Framework im Bereich der Code Access Security (CAS) versteckt sind [1], wird sich der eine oder andere Entwickler wehmütig an die gute alte Zeit zurückerinnern. Damals stellte eine frische Standardinstallation von Windows alle Dienstleitungen sofort zur Verfügung, sehr zur Freude der generell von Zeitnot geplagten Entwickler und Anwender. Allerdings freute sich da still und heimlich noch eine andere Klientel, was sich dann regelmäßig in Form von Fieberschüben aufgrund von Viren, Würmern oder sonstigem Getier bemerkbar machte. Mit dem .NET Framework begann eine neue Ära, in der einer ausführbaren Anwendung bereits in der Voreinstellung je nach Herkunft enge Fesseln angelegt werden. Während zuerst nur der Entwickler von diesem Paradigmenwechsel betroffen war, spürten beginnend mit Windows 2003 Server die Administratoren ebenfalls den frischen Wind. Auch wenn der Aufwand für beide steigt, will doch wohl niemand die guten alten (unsicheren) Zeiten wirklich zurück haben. Da die Benutzerfreundlichkeit (um nicht das unschöne Wort „Bequemlichkeit“ in den Mund nehmen zu müssen) aber eines der Geheimnisse für den Erfolg des Betriebssystems Windows war, sieht auch das .NET Framework einen bequemen Weg vor, solange die .NET-Anwendung von einem lokalen Laufwerk des Rechners aus gestartet wird. Dank der vom .NET Framework in den Namespaces System.Reflection, System.Security, System.Security.Policy und System.Security.Permissions bereitgestellten Klassen kann die Beispielanwendung in diesem Fall den Ausstattungsgrad des eigenen Sandkastens ermitteln, weil die Anwendung von der CLR (Common Language Runtime) mit uneingeschränkten Berechtigungen (FullTrust) ausgeführt wird. Die vom Beispielprogramm angezeigten Informationen fasst die folgende Aufzählung zusammen (der Kasten „Code Access Security (CAS) im Schnelldurchlauf“ hilft bei der Einordnung der Begriffe):

  • Aufrufpfad des Programms.
  • Name der Zone, in die die Anwendung von der CLR eingeordnet wurde.
  • Dateinamen der verschiedenen Konfigurationsdateien für die Sicherheitseinstellungen.
  • Zuordnung der Berechtigungsgruppen getrennt nach Computer (Machine) Organisation (Enterprise) und Benutzer (User), wobei der niedrigste Berechtigungssatz das Verhalten der Anwendung definiert (Prinzip des kleinsten gemeinsamen Nenners der Berechtigungen).
  • Aktuelle Berechtigungsmenge.
  • Benutzername im Active Directory.
Code Access Security (CAS) im Schnelldurchlauf Über die Codezugriffssicherheit steht ein Modell zur Verfügung, über das ein Administrator eigene Sicherheitsrichtlinien für den Zugriff auf Ressourcen oder das Ausführen von privilegierten Anweisungen direkt dem ausführbaren Modul zuordnen kann. Während das Betriebssystem bisher die Rechte bei den Win32-Anwendungen generell dem Benutzerkonto zugeordnet hat, erlaubt die CAS eine viel feinere Abstufung, da nun zum Beispiel auch die Fragen „Von wo aus wurde die Assembly geladen?“, „Von wem stammt die Assembly?“ oder gar „Welche Anwendung ruft diese Assembly auf?“ bei der Vergabe der Berechtigungen (Permission) berücksichtigt werden. Unter einer Berechtigung versteht man das Recht, eine so genannte Trusted Operation (wie zum Beispiel der Zugriff auf das Dateisystem, die Registry, die Ereignisanzeige, die Umgebungsvariablen oder gar auf die Benutzeroberfläche usw.) ausführen zu dürfen. Die Sicherheitsprüfung ist ein Kernbestandteil der CLR, sowohl der für das Laden einer Klasse zuständige Class Loader als auch der Just-in-Time-Compiler (JIT) beachten die CAS-Regeln. Bei der Frage, wie eine Berechtigung genutzt wird, kommen die Aktionen Demand, Assert, Deny, PermitOnly und LinkDemand ins Spiel. Eine Sicherheitsüberprüfung für das Berechtigungsobjekt kann über Demand angefordert oder über Assert teilweise blockiert werden. Über einen LinkDemand wird direkt am JIT die Prüfung des unmittelbaren Aufrufers beauftragt, sodass in Verbindung mit einer StrongNameIdentityPermission eine Klasse sicherstellt, dass sie nur von einem definierten Nutzer (Strong Name) eingebunden wird. Wenn .NET eine Assembly lädt, wird der Beweis (Evidence) über die Codeherkunft ermittelt, damit .NET genau die Berechtigungsmenge (Permission Set) der Privilegien zusammenstellen kann, die für diese Herkunft über die Sicherheitsrichtlinien (Policy) festgelegt wurden. Die CLR berücksichtigt sieben verschiedene Evidence-Typen, wobei vier davon (Site, Url, Zoneund ApplicationDirectory) die Herkunft des ausführbaren Programmcodes berücksichtigen. Die beiden Evidence-Typen StrongName und Publisherbeantworten die Frage, welcher Entwickler diesen Code geschrieben hat. Der verbleibende Evidence-Typ Hash (SHA1 mit einem 20-Byte-Hashcode) wird aus der Prüfsumme der Assembly gebildet und erlaubt die Prüfung auf eine bestimmte (nicht manipulierte) Codeversion, unabhängig von der offiziellen Versionsnummer. Diese sieben Evidence-Typen werden auch als Host Evidence bezeichnet, da die Host-Umgebung für die Implementierung zuständig ist. Unter .NET gibt es zwei Instanzen, die diese Beweise für die Vertrauenswürdigkeit sammeln können: Zum einen die CLR selbst und zum anderen der Host der Application Domain (also die Stelle, die eine Assembly lädt und ausführen lässt). Es dürfen nur diejenigen Beweise vorbringen, die als vertrauenswürdig (Sicherheitsrecht ControlEvidence) eingestuft wurden. Zurzeit berücksichtigt .NET gleich drei Hosts automatisch, neben der Windows-Shell und dem Internet Explorer darf auch ASP .NET die Beweise vorlegen. Damit die Berechtigungsmengen nicht mühsam jeder einzelnen Assembly zugeordnet werden müssen, unterteilt die CLR die Welt in fünf verschiedene vordefinierte Sicherheitszonen (Code Groups), wobei in der Zone My_Computer_Zone alle die Assemblies landen, die von einem lokalen Datenträger aus geladen wurden:
  • My_Computer_Zone
  • LocalIntranet_Zone
  • Trusted_Zone
  • Internet_Zone
  • Restricted_Zone

In der LocalIntranet_Zone landen in der Voreinstellung alle die Assemblies von einem entfernten Dateisystem, die über ein gemapptes Netzlaufwerk, einen UNC-Pfad (wie zum Beispiel \ServernameFreigabenameAssemblyName. dll) oder über eine HTTP-URL für WINS-Adresssen (wie z.B. http:// ServerName/VirtuellesWebverzeichnis/AssemblyName.dll) geladen werden. In der Zone Internet_Zone landen alle Assemblies, die keiner anderen Zone zugeordnet werden können. Beachten Sie bitte, dass dies auch für alle URLs gilt, bei denen die IP-Adresse genutzt wird (somit unterscheiden sich http://localhost und http://127.0.0.1 in der Zuordnung, obwohl beide ULRs den gleichen Rechner adressieren). Zusätzlich zu den vordefinierten Codegruppen können eigene Gruppen eingerichtet werden, wobei für diesen Schritt verschiedene Wege verfügbar sind. Zum einen die visuelle Konfiguration über die .NET Framework Configuration, die Script-Konfiguration über das Kommandozeilen-Tool Caspol.exe und als dritte Option das direkte Hantieren mit der SecurityManager-Klasse aus dem .NET-Framework. Jeder Codegruppe können Berechtigungsmengen (Permission Sets) zugeordnet werden, um auch bei den Berechtigungen nicht alles einzeln konfigurieren zu müssen. Die CLR stellt eine Menge von vordefinierten unveränderlichen Permission Sets zur Verfügung, die jedoch in Form einer Kopie erweitert werden können. Zum Beispiel enthält das Internet-Permission-Set alle die Berechtigungen, die für den Download aus dem Internet gelten sollen. Im Gegensatz dazu sorgt das FullTrust-Permission-Set dafür, dass der Programmcode alle Operationen uneingeschränkt ausführen darf.

Allerdings sammelt das Programm sofort beim Programmstart nur die Informationen über den Aufrufpfad, den Zonennamen sowie den Benutzernamen ein, alle anderen Daten sind erst über das Bearbeiten-Menü erreichbar (Listing 1).

Listing 1
--------------------------------------------------------

StatusBarMain.Text = String.Format( _
  "Im Active Directory angemeldet als Benutzer"{0}"", _
  Environment.UserName)
,
  Dim aAsm As System.Reflection.Assembly
  aAsm = System.Reflection.Assembly.GetExecutingAssembly()
  LabelAsm.Text = aAsm.CodeBase.ToString()
,
  Dim sBD As String = AppDomain.CurrentDomain.BaseDirectory
  Dim aSZ As SecurityZone = Zone.CreateFromUrl(sBD).SecurityZone
  LabelSecurityZone.Text = aSZ.ToString()

Als aktuell geltende Sicherheitszone zeigt das Beispielprogramm beim Start von einem lokalen Laufwerk die Zeichenkette MyComputer an. Erst beim Anklicken des Menüpunktes Bearbeitern | Daten anzeigen wird bei der Auflistung der Codegruppen erkennbar, warum die Anwendung beim Start vom lokalen Datenträger mit vollen Rechten ausgeführt wird. Im Programmfenster ist dann das Ergebnis in Listing 2 zu sehen.

Listing 2
--------------------------------------------------------------

UnionCodeGroup['All_Code']:FullTrust
UnionCodeGroup['All_Code']:Nothing
UnionCodeGroup['My_Computer_Zone']:FullTrust
UnionCodeGroup['All_Code']:FullTrust

Die Organisationskonfiguration (Enterprise) sowie die Benutzerkonfiguration (User) räumt allen ausführbaren Anwendungen (All_Code) uneingeschränkte Rechte ein, aber die Konfiguration des Computers (Machine) verbietet alles (Nothing). Hinter Nothing steckt eine leere Berechtigungsmenge, die nichts erlaubt. Über die Computerregeln hat der lokale Administrator dieses Rechners die Möglichkeit, die Regeln für .NET-Assemblies selbst zu definieren. Beim Aufruf über ein lokales Laufwerk ist ein Eingriff aber nicht notwendig, da die in der Standardkonfiguration des .NET Framework vordefinierte Codegruppe My_Computer_Zone die Beschränkung wieder aufhebt, da Nothing mit FullTrust überstimmt wird (eine Codegruppe kann festlegen, ob diese Rechte additiv oder exklusiv gelten sollen).

Sysadmin – wir haben ein Problem

Wird die Programmdatei nun auf die Festplatte des Servers verschoben und über ein gemapptes Netzlaufwerk gestartet, so scheint zuerst alles noch in Ordnung. Doch bereits die geänderte Zone (Intranet anstelle von MyComputer) gibt einen ersten Hinweis auf die Probleme, die nach dem Anfordern aller Daten deutlich werden. Die CLR würgt diesen Informationswunsch mit einem Veto vom Typ System.Security.Permissions.SecurityPermission ab, da das Benutzerkonto allein nicht mehr die verfügbaren Berechtigungen festlegt (Abbildung 1). &picture_0 Das Beispielprogramm kann beim Start über das Netzlaufwerk erst dann zur uneingeschränkten Kooperation überredet werden, wenn mit Administratorrechten über die .NET-Framework-Konfiguration unterhalb von All_Code eine neue Codegruppe angelegt wird. Als kennzeichnendes Merkmal, über das eine Assembly dieser neuen Codegruppe automatisch zugeordnet werden soll, wurde im Beispiel der Strong Name ausgewählt, mit dem die Beispielanwendungen (Visual-Basic- und C#-Fassung) signiert wurden (Abbildung 2).

Die Rechte werden aufgebohrt

Wird nun der Menüpunkt Bearbeiten | Daten anzeigen aufgerufen, so zeigt das Beispielprogramm die Codegruppenzuordnung aus Listing 3 an.

Listing 3
---------------------------------------------------------

UnionCodeGroup['All_Code']:FullTrust
UnionCodeGroup['All_Code']:Nothing
UnionCodeGroup['LocalIntranet_Zone']:LocalIntranet
UnionCodeGroup['dotnetMagazin']:FullTrust
UnionCodeGroup['All_Code']:FullTrust

Da die Anwendung von einem Netzlaufwerk gestartet wird, sortiert die CLR das Programm in die vordefinierte Codegruppe LocalIntranet_Zone ein, die allerdings nur die eingeschränkte Berechtigungsmenge LocalIntranet erlaubt. Allerdings gilt zusätzlich die uneingeschränkte Berechtigungsmenge (FullTrust) der soeben neu erstellten Codegruppe dotnetMagazin, sodass sich die Beispielanwendung genauso verhält, wie beim Aufruf über ein lokales Laufwerk. Das Experiment hat gezeigt, wie das Netzlaufwerkproblem gelöst wird. Spannender ist jedoch die Frage, wie das Problem von vornherein vermieden werden kann, wenn die .NET-Anwendung auf diesem Rechner installiert wird. Die Antwort auf diese Frage hängt davon ab, in welchem Umfeld die Anwendung betrieben wird. Es stehen mindestens drei Alternativen zur Verfügung:

  • In einem Firmennetzwerk ist der Administrator in der Lage, die einmalig von Hand zusammengestellte Richtlinienstruktur über den Weitergabepaketassistenten der .NET-Framework-Konfiguration als MSI-Setup zusammenzupacken. Dieses Setup überschreibt dann bei den zu konfigurierenden Rechnern die Standardeinstellung durch die definierte Richtlinienstruktur des Unternehmens.
  • Während der Weitergabepaketassistent der .NET-Framework-Konfiguration eine „Alles-oder-Nichts“-Lösung ist, erlaubt das Kommandozeilen-Tool Caspol.exe einen „chirurgischen“ Eingriff, indem ein Skript die Konfiguration von einer zusätzlichen Codegruppe übernimmt.
  • Das Installationsprogramm der .NET-Anwendung (MSI-Setup) wird um eine Installer-Klasse erweitert, die die benötigte Codegruppe während des Setups anlegt. Allerdings gilt auch hier, dass zur Änderung der Computerberechtigungsgruppen für das Setup Administratorrechte benötigt werden.
Das Setup-Projekt

Von den verfügbaren Optionen erfüllt das MSI-Setup der Beispielanwendung die Anforderungen am besten – denn im Normalfall soll die Anwendung ja auch lokal installiert werden. Nur für den Fall, dass eine Unternehmensrichtlinie den lokalen Aufruf nicht vorsieht, wird die Codegruppe für FullTrust-Berechtigung angelegt, sodass die Anwendung auch dann noch problemlos aufgerufen werden kann, wenn diese nur von einem Netzlaufwerk aus gestartet werden soll. Nachdem das Grundgerüst des Setup-Projekts steht, wird der Projektmappe ein weiteres Projekt für eine Klassenbibliothek hinzugefügt. Damit das MSI-Setup die neue Klasse einbindet, muss diese von System.Configuration.Install.Installer abstammen und mit dem Attribut [RunInstaller(true)] gekennzeichnet werden.

Die eigene Installer-Klasse wird eingebunden

Der einfachste Weg, eine derartige Klasse zu erhalten, führt über die Vorlage Installer Class – sodass nur noch die geerbten Methoden Install, Commit und Uninstall überschrieben werden müssen. Einen Anhaltspunkt über die notwendigen Schritte findet sich in [3], sodass die Checkliste für eigene Anpassungen sehr kurz ist:

  • Es wird ein sprechender, eindeutiger Name für die neue Codegruppe festgelegt.
  • Weil der Strong Name für die Zuordnung herangezogen werden soll, muss nun auf StrongNameMembershipCondition zurückgegriffen werden. Über die StrongNamePublicKeyBlob-Klasse werden die öffentlichen Schlüsselinformationen des Strong Name aufbereitet, wobei die Rohdaten vom Kommandozeilen- Tool secutil.exe stammen. Mit dem Aufruf „secutil -c -s VBWinApp. exe > output.txt“ schreibt dieses Tool die gesuchte Information in eine Datei, wobei dann die Public-Key-Zeichenkette über die Zwischenablage in das Klassenbibliotheksprojekt kopiert wird.
  • Die Klassenbibliothek wird mit in das Setup-Projekt aufgenommen.
  • Im Setup-Projekt wird der Custom-Actions-Editor aufgerufen, um jeweils in den Ordnern Install, Commit und Uninstall einen Verweis auf die Klassenbibliothek mit der Installer-Klasse hinzuzufügen (Abbildung 3).

Damit sind alle Zutaten fertig. Wenn die Anwendung über das Setup auf einem Rechner installiert wird, richtet das Setup dabei die eigene Codegruppe dotnetMagazin ein. Falls nun der Anwender die Programmdateien auf einem Netzlauf ablegt, kann er die Anwendung trotzdem uneingeschränkt nutzen. Wird das Programm später über die Systemsteuerung | Software wieder deinstalliert, räumt die eigene Installer-Klasse auch die Codegruppe dotnetMagazin wieder ab.

Andreas Kosch beschäftigt sich in seinem Alltag mit der Konzeption und Entwicklung von dreischichtigen Datenbankanwendungen für den MS SQL Server (Schwerpunkt: .NET Enterprise Services). Obwohl der Schwerpunkt dabei auf C# liegt, kommt der Bequemlichkeit geschuldet regelmäßig auch Visual Basic zum Einsatz.

Links & Literatur
  1. Brian A. LaMacchia et al., .NET Framework Security, Addison-Wesley 2002
  2. Andreas Kosch, Managed Bodyguard, in: dot.net magazin 6.05
  3. http://www.windowsforms.net/Applications/application.aspx?PageID=40&tabindex=8
  4. Don Box zum Thema CAS-Security
Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -