Anwendungssicherheit im .NET Framework:

Eine kurze Einführung

von Marcel Zinnow

 

Anwendungen, die nicht innerhalb der .NET-Runtime ausgeführt werden, erhalten die gleichen Rechte wie der eingeloggte Benutzer. Da dieser oft über Administratorrechte verfügt, entsteht eine große Sicherheitslücke – ein Problem gerade in Bezug auf Anwendungen, die aus dem Internet heruntergeladen werden. Denn bösartige Programme können so zum Beispiel beliebige Dateien löschen, da sie uneingeschränkten Zugriff auf die Festplatte besitzen. Um diese Sicherheitslücke zu schließen, ist mit dem .Net Framework ein Sicherheitskonzept eingeführt worden.

 

Das .NET-Sicherheitskonzept

Das Sicherheitsmodell im Microsoft .NET Framework ist die Code Access Security (CAS). Durch dieses Modell wird nicht privilegierter und nicht vertrauenswürdiger Code an der Ausführung von sicherheitskritischen Aktionen gehindert. Sicherer Code basiert auf Rechten und Beweisen. Dank der Vergabe von Rechten kann der Code geschützte Operationen ausführen. Um zum Beispiel eine Datei löschen zu können, muss der Benutzer das Recht zum Löschen besitzen. Beweise sichern die Echtheit einer Assembly durch die Prüfung bestimmter Eigenschaften im Rahmen der Sicherheitsrichtlinien des Systems.

Code, der sicherheitsrelevante Aufgaben durchführen will, muss seinerseits das Recht zur Ausführung dieser Aufgabe von der Common Language Runtime (CLR) erfragen. Dabei prüft die CLR mit einem Durchlauf durch die Aufrufliste (engl. „call stack”), welche Rechte der Assembly durch die Zugehörigkeit zu einer Sicherheits-gruppe gewährt wurden, und gewährt oder verbietet ihrerseits die Ausführung dieser Aufgabe.

Berechtigungen legen fest, ob eine Assembly bestimmte Aktionen ausführen darf. Sie erlauben den Zugang zu geschützten Ressourcen oder den Zugriff auf geschützte Operationen. .NET stellt eine ganze Reihe von Standardberechtigungen bereit. Zum Beispiel legt die Berechtigung „Registrierung“ fest, ob die Assembly Einträge in der Windows-Registry zu dem angegebenen Schlüssel lesen, verändern oder erstellen darf.

Der Compiler für .NET-Sprachen erzeugt einen standardisierten Zwischencode (CIL). Bei Ausführung der Anwendung übersetzt ein in der CLR integrierter JIT-Compiler den Zwischencode in Maschinencode, der dann direkt vom Prozessor ausgeführt werden kann. Im Gegensatz zu Anwendungen, die direkt in Bytecode kompiliert werden, ermöglicht es dieser Zwischenschritt der CLR, die Berechtigungen von Anwendungen vor Ausführung zu überprüfen.

 

Prozess der Rechtevergabe

Wird eine Assembly durch die CLR geladen, so wird diese vor deren Ausführung inspiziert. Hierbei sammelt die CLR zuerst die Beweise für die Assembly. Beweise können die Herkunft einer Assembly wie z. B. das Anwendungsverzeichnis, die URL oder die Site beschreiben. Durch den Hashwert, den starken Namen oder den Herausgeber einer Assembly kann auch die Identität als Beweis gelten.

Basierend auf den Beweisen, werden eine oder mehrere Codegruppen der Assembly zugewiesen. Codegruppen verknüpfen Assemblies mit den Berechtigungssätzen (Sammlung mehrerer Berechtigungen). Sie enthalten die Mitgliedschaftsbedingung (Beweis) und den Berechtigungssatz, der dieser Codegruppe zugeordnet ist.

Codegruppen ähneln den Benutzergruppen von Windows. Möchte ein Administrator einer bestimmten Auswahl von Benutzern Berechtigungen gewähren, dann erstellt er eine Benutzergruppe mit der gewünschten Berechtigung und fügt dann die Benutzer dieser Benutzergruppe hinzu. Bei den Codegruppen müssen die Anwendungen allerdings nicht explizit zugewiesen werden. Hier erfolgt die Zuordnung über die Beweise. Assemblies können auch verschiedenen Codegruppen zugewiesen werden. Sie erhalten dann alle Berechtigungen (Vereinigungsmenge), die den verschiedenen Codegruppen zugewiesen sind. Zusätzlich können die Codegruppen auch ineinander geschachtelt werden. Dies bedeutet, dass die Berechtigungen einer Assembly nur zugewiesen werden, wenn sie alle Beweisanforderungen sowohl der übergeordneten als auch der untergeordneten Codegruppen (Schnittmenge) erfüllt.

Eine oder mehrere Codegruppen werden durch logisches Zusammenfassen zu einer Sicherheitsrichtlinie zusammengefasst. Anhand dieser Sicherheitsrichtlinien kann die CLR bestimmen, wie der Security Manager die Rechte der Assembly zuweist.

Die unten stehende Tabelle zeigt die vier Ebenen Unternehmen, Computer, Benutzer und Anwendungsdomäne, in die eine Sicherheitsrichtlinie gegliedert werden kann. Die Sicherheitsrichtlinien bieten damit Administratoren flexible Möglichkeiten, CAS-Einstellungen auf mehreren Ebenen zu konfigurieren.

Der Berechtigungssatz, den eine Assembly vom Security Manager zugewiesen bekommt, ist der minimale Satz an Berechtigungen (Durchschnitt) aller Richtlinien-
ebenen. Die Sicherheitspolitik auf untererEbene kann somit nicht mehr erweitert, sondern nur noch weiter verschärft werden.

Die oben stehende Grafik „Richtlinienebenen“ veranschaulicht die Durchschnitts-bildung der Berechtigungssätze der vier Ebenen. Der gelbe Bereich repräsentiert die Permissions, die der Assembly schließlich zugewiesen werden.

 

Policy Enforcement

Die Rechtevergabe ist ein komplexer Prozess, der vor jeder Ausführung einer gemanagten .NET-Anwendung durchgeführt wird. Wozu passiert das überhaupt? Wozu braucht eine Assembly die Rechte, die ihr zugewiesen werden? 

Die Rechte einer Assembly werden immer dann geprüft, wenn sie auf eine geschützte Ressource zugreifen will. Die Technologie, die das ermöglicht, ist der Security Stack Walk.

 

Demand

Der Grundstein für CAS ist der Prozess „demand“. Vertrauenswürdiger Code und
die Runtime selbst führen eine Anforderung („demand“) aus, bevor diese auf eine

geschützte Ressource zugreift. Der Code fordert eine Berechtigung bzw. einen Berechtigungssatz seines Aufrufers an. Jeder Aufrufer des Aufrufstacks bis zur Main-Methode wird somit auf seine angeforderten Berechtigungen überprüft.

Damit wird sichergestellt, dass weniger vertrauenswürdiger Code durch Ausnutzen von vertrauenswürdigem Code auf geschützte Ressourcen zugreifen kann.

Stellen Sie sich z. B. vor: Code A benutzt eine Komponente in Code B, die wiederum ein FileStreamObject (implementiert in Code C) benutzt, der Zugriff auf das Da-
teisystem benötigt. Die Klasse FileStream aus der Framework Class Library (FCL) ist so implementiert, dass die benutzten Methoden zuerst entsprechende Berechtigungen anfordern, um auf das Dateisystem zuzugreifen, bevor sie ihre eigentliche Funktionalität durchführen. Die CLR wird nun diese Berechtigungsanforderung für jeden Aufrufer im Call Stack dieser Methode durchführen. Ist die Überprüfung der Berechtigungsanforderung für jeden Auf-
rufer erfolgreich durchgeführt worden, kann im FileStreamObject auf die geschützte Ressource zugegriffen werden. Besitzt einer der Aufrufer jedoch keine der angeforderten Berechtigungen, wird die CLR eine Security Exception werfen.

Fazit

Durch die rasante Entwicklung von verteilten und komponentenbasierten Anwendungen wird die Bedeutung der in .NET verwendeten codebasierten Sicherheit immer größer. Das .NET Framework bietet ein umfassendes Sicherheitssystem, das es dem Entwickler auf eine flexible und elegante Art ermöglicht, sichere Anwendungen zu entwickeln. Für einen Anwendungsentwickler läuft der CAS-Mechanismus transparent ab. Er wird die Security Exceptions vom .NET Framework abfangen und entsprechend darauf reagieren, ohne umfassende Kenntnisse in CAS zu benötigen. Anders sieht es bei einem Framework- oder Bibliothekenentwickler aus. Dieser sollte sich mit CAS genauer auseinandersetzen und bei Zugriff auf zu schützende Ressourcen die notwendigen Berechtigungen anfordern und gegebenenfalls mit entsprechenden Exceptions reagieren.  

 


zurück zur Artikel-Übersicht