Neues zur Codezugriffs-Sicherheit im .NET Framework 2.0

Veröffentlicht: 21. Dez 2005

Von Mike Downen

Sicherheit umfasst im Microsoft .NET Framework eine Vielzahl von Technologien: Rollenbasierte Sicherheit in Basisklassenbibliotheken (BCL - Base Class Libraries) und in ASP.NET, Kryptografieklassen in der BCL und eine neue Unterstützung von Zugriffssteuerungslisten (ACLs - Access Control Lists) sind nur einige wenige von vielen Beispielen. Die Codezugriffs-Sicherheit (CAS - Code Access Security) ist eine der Technologien, die im von der Common Language Runtime (CLR) bereitgestellten Sicherheitsspektrum von .NET enthalten sind. Dieser Artikel erläutert die Bedeutung von CAS in .NET und einige wichtige neue Funktionen und Änderungen von CAS im .NET Framework 2.0.

Die meisten Entwickler, die mit .NET Framework arbeiten, müssen im Prinzip nicht mehr über CAS wissen, als dass es CAS gibt. Wie bei Gleitkommazahlen handelt es sich bei CAS um eine Funktion von Framework, bei der ein ausführliches und tief greifendes Wissen sehr nützlich sein kann, das für die meisten Anwendungen jedoch nicht erforderlich ist.

Auf dieser Seite

Warum CAS?
Sandbox-Berechtigungen
Hosts und Frameworks
Anwendungsdomänen und Sicherheit
Definieren der Sandbox
Vorgehensweise beim Hosten
CAS und Frameworks
Sicherheitstransparenter Code
Verwenden von Transparenz
Schlussbemerkung
Der Autor

Warum CAS?

Im Zusammenhang mit dem Thema Zugriffssteuerung werde ich auch oft nach rollenbasierter Sicherheit gefragt: die Steuerung von Zugriff auf Ressourcen auf Grundlage der Benutzeridentität. Die Schwierigkeiten beim Verstehen von CAS liegen darin begründet, dass CAS nicht auf Benutzeridentitäten basiert ist. Stattdessen basiert CAS auf der Identität des ausgeführten Codes, einschließlich Informationen wie Herkunft (z. B. der lokale Computer oder das Internet), Ersteller und Signierer. Die Aktionen, die der Code durchführen kann, und die Ressourcen, auf die der Code zugreifen kann, sind auf Grundlage dieser mit dem Code und seiner Identität verbundenen "Beweise" eingeschränkt.

Warum sollten Sie die Funktion von Code auf Grundlage seiner Identität einschränken? In den häufigsten Fällen ist diese Vorgehensweise nicht üblich. Beispielsweise könnten Sie ein schickes und teures Grafikbearbeitungsprogramm ausführen, das auf jede Ressource zugreifen kann, auf die auch Sie als der Benutzer, der das Programm ausführt, zugreifen können (Dateien, Registrierungseinstellungen usw.). In diesem Fall kennen Sie den Anbieter der Software und vertrauen diesem, und Sie sind bereit, dieser Software auf der Plattform, auf der sie ausgeführt wird, eine hohe Zugriffsebene zu gewähren. Anwendungen werden normalerweise mit dem Benutzerkonto ausgeführt, das über die wenigsten, gerade noch erforderlichen Berechtigungen verfügt, um eine versehentliche Beschädigung der Daten auf dem Computer zu vermeiden. Andererseits spielt die Vertrauenswürdigkeit der Anwendung selbst hierbei keine Rolle.

Es gibt jedoch Situationen, in denen Sie Code ausführen möchten, dessen Autor Ihnen nicht bekannt ist oder dem Sie nicht vollständig vertrauen. Diese Situation tritt heutzutage meistens beim Durchsuchen des Internets auf. Moderne Browser führen auf den besuchten Websites oft auch Code aus. Bei diesem Code handelt es sich gewöhnlich um JavaScript oder DHTML, jedoch kann es sich auch um andere Typen von ausführbaren Dateien handeln, die vom Browser erkannt werden. Wenn Browser diesen Code auf dem lokalen Computer ausführen, geschieht dies in einer Sandbox. Eine Sandbox ist eine eingeschränkte Ausführungsumgebung, durch die die Ressourcen gesteuert werden, auf die der Code auf dem Computer zugreifen kann. Diese Sandbox ist dringend notwendig - andernfalls würde relativ anonymer Code aus dem Internet in der Lage sein, jeden Tag Ihre persönlichen Dateien zu lesen und auf dem Computer Viren zu installieren. Viele Browser stellen verschiedene Ebenen für "Sandboxing" bereit, basierend auf der Herkunft des ausgeführten Codes. Beispielsweise werden beim Microsoft Internet Explorer Zonen definiert. Code aus der Internetzone verfügt im Vergleich zu Code von vertrauenswürdigen Sites über eingeschränkten Zugriff. Sicherheitsschwachstellen werden ausgenutzt, wenn ein Softwarefehler vorliegt, durch den die Sandboxregeln erzwungen werden, oder der Benutzer wird durch einen Trick dazu gebracht, die Ausführung von Code außerhalb der Sandbox zuzulassen.

Das Ausführen von Code einer Website in einem Browser ist ein häufiges Szenario für Sandboxing und Sicherheit auf der Grundlage von Codeidentität. CAS in der CLR stellt einen allgemeinen Mechanismus bereit, um Code auf Grundlage der Codeidentität in einer Sandbox auszuführen. Dies ist der größte Vorteil und das häufigste Anwendungsgebiet. Der Internet Explorer verwendet CAS, um verwalteten Code von Websites, die mit dem Browser geöffnet werden, in einer Sandbox auszuführen (entweder Steuerelemente oder eigenständige Anwendungen). CAS wird zum Ausführen von Anwendungen von einer Netzwerkfreigabe im lokalen Intranet in einer Sandbox verwendet. Visual Studio Tools für Office (VSTO) nutzen CAS, um verwaltete Add-Ins für Microsoft Office-Dokumente zu hosten. In Serverszenarios kommt CAS in ASP.NET für Webanwendungen und im SQL Server 2005 für verwaltete gespeicherte Prozeduren zum Einsatz. CAS tritt also bei vielen Szenarios in Erscheinung, gewöhnlich aber im Hintergrund.

Sandbox-Berechtigungen

Ich werde oft von Entwicklern gefragt, was sie über CAS wissen sollten. Für Anwendungsentwickler hängt die Antwort davon ab, ob diese eine Anwendung schreiben, die in einer Sandbox ausgeführt wird, wie z. B. ein verwaltetes Steuerelement im Internet Explorer. Entwickler müssen sich in diesem Fall über Folgendes im Klaren sein:

  • welche Aufgaben in der Sandbox durchgeführt werden sollen

  • ob dadurch ausreichend Funktionalität zur Ausführung der Anwendung gewährleistet ist

  • wie die Vertrauenswürdigkeit der Anwendung gesteigert wird, um gegebenenfalls weitere Berechtigungen zu erhalten

Beispielsweise verwenden verwaltete Steuerelemente im Browser einen Standardsatz von Sandboxberechtigungen: den Internet-Berechtigungssatz. Hinsichtlich des Ressourcenzugriffs gewährt diese Sandbox der Anwendung die Berechtigung, "sichere" Benutzeroberflächen-Elemente zu erstellen - transparente Fenster werden z. B. als unsicher erachtet, da diese für Spoofing oder Man-in-the-Middle-Angriffe verwendet werden können. Des Weiteren ist die Anwendung in der Lage, Internetverbindungen mit ihrer Herkunftssite herzustellen, Zugriff auf Dateisystem und Drucker mit Zustimmung des Benutzers zu erhalten und eine begrenzte Datenmenge in einem isolierten Speicher abzulegen (ähnlich wie Cookies im Internet Explorer). Anwendungen können weder zufällige Teile des Dateisystems oder der Registrierung noch Umgebungsvariablen lesen. Darüber hinaus wird die Anwendung durch die Sandbox daran gehindert, Verbindungen mit einer SQL Server-Datenbank herzustellen, COM-Objekte oder anderen unverwalteten Code aufzurufen. Verschiedene Hosts definieren unter Umständen unterschiedliche Sandboxes. Beispielsweise definieren SQL Server und ASP.NET verschiedene Berechtigungssätze für wenig vertrauenswürdige Anwendungen. In Abbildung 1 werden diese Sandboxberechtigungen dargestellt.

Sobald Ihnen die Optionen für eine Sandbox bekannt sind, können Sie entscheiden, ob eine Sandbox-Anwendung Ihren Anforderungen gerecht wird. Wenn Sie beispielsweise für den Internet Explorer ein verwaltetes Steuerelement schreiben und eine Verbindung mit einer SQL-Datenbank herstellen möchten, kann das Steuerelement in der Standardeinstellung nicht in der Sandbox ausgeführt werden. Entweder müssen Sie Ihr Vorhaben ändern (beispielsweise, indem Sie über einen Webdienst auf Daten zugreifen, der auf dem Server des Steuerelements bereitgestellt wird), oder Sie erhöhen auf dem Client-Computer die Vertrauensstufe des Steuerelements. Bei verwalteten Steuerelementen im Browser müssen CAS-Richtlinien bereitgestellt werden, um die Vertrauenswürdigkeit sowohl der Herkunftssite des Steuerelements als auch des Steuerelements selbst zu steigern. Hosts verfügen über unterschiedliche Mechanismen zum Vertrauen von Anwendungen. Um die Vertrauensstufe einer ASP.NET-Anwendung zu ändern, müssen Sie in einer Konfigurationsdatei eine Einstellung ändern.

In einigen Fällen muss die Anwendung in einer Sandbox ausgeführt werden, da es unwahrscheinlich ist, dass Benutzer diese Anwendung auf andere Weise installieren und ausführen. Angenommen, Sie schreiben ein einfaches Umfragesteuerelement für eine Website. Dem Benutzer werden durch das Steuerelement Fragen gestellt, und die Antworten werden aufgezeichnet. Es ist unwahrscheinlich, dass jemand für ein so einfaches Steuerelement eine voll vertrauenswürdige Anwendung herunterlädt und ausführt. Es kann jedoch vorkommen, dass Sie eine vertrauenswürdige Anwendung schreiben und dennoch davon profitieren, diese Anwendung in der Sandbox auszuführen. In Abbildung 2 werden die Vertrauensstufen mit und ohne Sandboxing dargestellt. Wenn die Anwendung darüber hinaus mit voller Vertrauenswürdigkeit ausgeführt werden muss, stellen Sie sicher, dass diese sich in teilweise vertrauenswürdigen Umgebungen trotzdem ordnungsgemäß verhält. Weitere Informationen finden Sie in der Randbemerkung "Handling Partial Trust Gracefully" (in englischer Sprache).

Normalerweise ist es wesentlich leichter, eine Sandbox-Anwendung bereitzustellen. Mit ClickOnce werden z. B. Sandbox-Anwendungen einfach ausgeführt, ohne dass eine Aktion des Benutzers erforderlich ist. Weitere Informationen zu ClickOnce finden Sie unter ClickOnce: Deploy and Update Your Smart Client Projects Using a Central Server und Escape DLL Hell: Simplify App Deployment with ClickOnce and Registration-Free COM (in englischer Sprache).

Sandbox-Anwendungen sind darüber hinaus im Allgemeinen zuverlässiger. Wenn SQL Server möglichst viele verwaltete gespeicherte Prozeduren mit niedrigster Vertrauensstufe von SQL Server ausführt, ist weniger Code vorhanden, der über vollständigen Zugriff auf den Server verfügt und aus diesem Grund Daten auf dem Server beschädigen kann (sei dies nun mit böswilliger Absicht oder versehentlich).

Visual Studio 2005 unterstützt das Erstellen von Sandbox-Clientanwendungen, die mit ClickOnce bereitgestellt werden, sehr viel stärker. Auf der Projekteigenschaften-Seite im Sicherheitsbereich werden die meisten Aufgaben durchgeführt (siehe Abbildung 3). An dieser Stelle aktivieren Sie Sicherheitseinstellungen und legen die Zone fest, die Sie für die Anwendung vorgesehen haben. Für Sandboxanwendungen wird gewöhnlich die Internetzone ausgewählt. Mit der Schaltfläche zum Ermitteln von Berechtigungen können Sie eine grobe Abschätzung der für die Anwendung erforderlichen Berechtigungen anzeigen. Weiterhin können Sie feststellen, ob die Größe der Anwendung für die Sandbox geeignet ist (diese Berechnungsfunktion steht auch mit dem Befehlszeilentool permcalc zur Verfügung, das mit dem .NET Framework 2.0 SDK geliefert wird).

Sicherheitsbereich in Visual Studio 2005
Abbildung 3 Sicherheitsbereich in Visual Studio 2005

Sie sollten unbedingt beachten, dass es sich hierbei um eine eher grobe, normalerweise konservative Abschätzung mithilfe einer rein statischen Analyse handelt. Sie sollten eine Anwendung immer mit den Berechtigungen testen, mit denen diese ausgeführt werden soll. Debuggen Sie hierzu einfach die Anwendung nach dem Festlegen der vorgesehenen Zone. Die Anwendung wird von Visual Studio mit den Berechtigungen ausgeführt, die Sie im Sicherheitsbereich festgelegt haben.

Hosts und Frameworks

Wenn Sie Hosts oder Frameworks schreiben, müssen Sie mehr über Sandboxes wissen als nur die Grundlagen. Host-Entwickler sollten damit vertraut sein, wie sie wenig vertrauenswürdigen Code hosten. Framework-Entwickler müssen wissen, wie sie Frameworks oder Bibliotheken schreiben, die wenig vertrauenswürdigem Code Funktionen bereitstellen.

Bevor ich jedoch diese Probleme erläutere, möchte ich ein Thema ansprechen, das oft für Verwirrung sorgt: die Ausführung mit niedrigster Berechtigungsebene. Die Ausführung mit niedrigster Berechtigungsebene betrifft das Ausführen von Code mit Mindestberechtigungen. Dadurch wird der Schaden eingegrenzt, der durch Ausnutzen eines Codefehlers hervorgerufen werden kann. Für die Sicherheit von Windows ist es immer von Vorteil, Programme mit der Benutzeridentität auszuführen, die über möglichst geringe Berechtigungen verfügt (z. B. ein normaler Benutzer anstelle eines Admin-Benutzers). Bei CAS bedeutet die Ausführung mit niedrigster Berechtigungsebene, dass die Anwendung oder Bibliothek mit einem minimalen Satz von CAS-Berechtigungen ausgeführt wird, die für das Durchführen von Aufgaben erforderlich sind. Obwohl die Ausführung mit niedrigster Berechtigungsebene im Allgemeinen eine empfehlenswerte Methode ist, so hat sie doch ihre Einschränkungen. Beispielsweise muss fast der gesamte Host- oder Frameworkcode mit einigen wesentlichen Berechtigungen ausgeführt werden, die in der Standardsandbox nicht vorhanden sind. Von diesem Code müssen häufig Win32-APIs oder anderer nicht verwalteter Code und Steuerressourcen auf dem Computer aufgerufen werden, wie z. B. Dateien, Registrierungsschlüssel, Prozesse und andere Systemobjekte. Da diese Art von Code bereits eine hohe Berechtigungsebene benötigt, ist es hinsichtlich der Sicherheit im Allgemeinen nicht der Mühe Wert, ein oder zwei Berechtigungen zu entfernen, wenn man bedenkt, dass vielen wesentlichen Berechtigungen volle Vertrauenswürdigkeit gewährt werden kann.

Sie sollten sich eher dem Überwachen und Testen des Codes zuwenden, um sicherzustellen, dass dieser vor böswilligen Aufrufern geschützt ist. (In Zusammenhang mit CAS bedeutet die Ausführung mit voller Vertrauenswürdigkeit, dass der Code über dieselben Berechtigungen für das System verfügt wie der Benutzer, der den Code ausführt. Wenn der Prozess, der den voll vertrauenswürdigen Code ausführt, nicht über Administratorrechte verfügt, hat auch voll vertrauenswürdiger Code keinen unbegrenzten Zugriff auf die Ressourcen des Computers.) Um dieses Vorgehen zu vereinfachen, enthält .NET Framework 2.0 eine neue Technologie, die sicherheitstransparenter Code genannt wird. Diese Technologie wird weiter unten in diesem Artikel zusammen mit weiteren Fragen bei der Frameworkentwicklung erörtert. Ich möchte mich jedoch zunächst mit Hosting befassen.

Im Allgemeinen bedeutet Hosting, dass die CLR verwendet wird, um Code im Kontext einer anderen Anwendung auszuführen. Beispielsweise hostet SQL Server 2005 die Laufzeit zum Ausführen gespeicherter Prozeduren, die in verwaltetem Code geschrieben sind. Ich werde mich hier auf die sicherheitsrelevanten Aspekte von Hosting beschränken und mit einer Übersicht über Anwendungsdomänen beginnen. Dennoch bleibt noch einiges über Hosting zu sagen - weitere Informationen finden Sie im Buch Customizing the Microsoft .NET Framework Common Language Runtime (Microsoft Press®, 2005) von Stephen Pratschner (in englischer Sprache).

Anwendungsdomänen und Sicherheit

Anwendungsdomänen stellen Unterprozess-Isolation für verwalteten Code bereit. Das heißt, dass jede Anwendungsdomäne über einen eigenen Statussatz verfügt. Prüfbarer Code in einer Anwendungsdomäne kann Code oder Daten in einer anderen Anwendungsdomäne nicht manipulieren, solange keine durch die Hostingumgebung erstellten Schnittstellen vorhanden sind, die eine solche Interaktion ermöglichen. Wie funktioniert das? Prüfbar typsicherer Code (standardmäßig sowohl vom C#- als auch vom Visual Basic .NET-Compiler erstellt) kann nicht beliebig auf den Arbeitsspeicher zugreifen. Jede Anweisung wird von der Laufzeit mithilfe eines Satzes von Überprüfungsregeln überprüft, um sicherzustellen, dass diese Anweisung typsicher auf den Arbeitsspeicher zugreift. Aus diesem Grund kann die Laufzeit die Isolation von Anwendungsdomänen beim Ausführen von nachprüfbarem Code gewährleisten, und sie kann verhindern, dass nicht nachprüfbarer Code ausgeführt wird.

Durch diese Isolation ist es einem Host möglich, Code mit verschiedenen Vertrauensstufen im demselben Prozess sicher auszuführen. Wenig vertrauenswürdiger Code kann in einer separaten Anwendungsdomäne entweder von vertrauenswürdigem Hostcode oder anderem wenig vertrauenswürdigen Code ausgeführt werden. Die Anzahl der Anwendungsdomänen, die zum Hosten von wenig vertrauenswürdigem Code benötigt werden, hängt von der für den Host vorgesehenen Isolationssemantik ab. So erstellt Internet Explorer beispielsweise für verwaltete Steuerelemente eine Anwendungsdomäne pro Site. Steuerelemente von einer Site können in derselben Anwendungsdomäne interagieren, jedoch können diese keine Steuerelemente einer anderen Site beeinträchtigen (oder in böswilliger Absicht nutzen).

Anwendungsdomänen-Firewall
Abbildung 4 Anwendungsdomänen-Firewall

CAS ermöglicht das Festlegen der Vertrauensstufe von Code, während dieser geladen wird. Hierbei werden über Richtlinien Beweise zu Berechtigungen zugeordnet. Darüber lässt sich mit CAS die Vertrauensstufe von Anwendungsdomänen während der Erstellung festlegen. Im .NET Framework 1.1 legen Sie hierzu für die Anwendungsdomäne Beweise fest, die durch Richtlinien einem Berechtigungssatz zugeordnet werden. Wann immer die Ablaufsteuerung zur Anwendungsdomäne übergeht, wird die Gewährung von Berechtigungen für die Anwendungsdomäne wie bei Assemblys dem Stapel hinzugefügt und während jedes Stackwalks beim Auswerten von Anforderungen von dieser Anwendungsdomäne berücksichtigt. Dieser Mechanismus, Anwendungsdomänen-Firewall genannt (siehe Abbildung 4), verhindert anwendungsdomänen-übergreifende Köderangriffe und stellt sogar einen weiteren Isolationsmechanismus bereit, um Code zwischen Anwendungsdomänen zu isolieren.

Mit CAS können Sie Code (Assemblies) in eine Anwendungsdomäne mit verschiedenen Vertrauensstufen (Berechtigungen) laden. Dies ist jedoch nicht die beste Vorgehensweise, um Code sicher in einer Sandbox auszuführen. Da der gesamte Code in einer Anwendungsdomäne denselben Status hat, ist es schwierig, höhere Berechtigungsebenen unter mehreren Assemblies in einer Anwendungsdomäne zu verhindern. Angenommen, Sie laden eine Assembly mit reiner Ausführungsberechtigung und eine weitere Assembly mit dem LocalIntranet-Berechtigungssatz. Der ersten Anwendungsdomäne (nur mit Ausführungsberechtigung) kann unter Umständen der LocalIntranet-Berechtigungssatz zugewiesen werden, wenn der Code nicht mit größter Sorgfalt für dieses Szenario geschrieben wurde. Außerdem können Sie nicht mehr die Vorteile der Anwendungsdomänen-Firewall nutzen. Es ist demnach sinnvoll, mehrere Anwendungsdomänen zu erstellen, die zu isolierenden Code hosten, selbst wenn dieser mit derselben Vertrauensstufe ausgeführt wird. Internet Explorer verfährt beispielsweise so mit Steuerelementen von verschiedenen Sites.

Statt mehrere Assemblies in eine einzelne Anwendungsdomäne mit verschiedenen Vertrauensstufen zu laden, empfehle ich ein einfaches Sicherheitsmodell und die Verwendung separater Anwendungsdomänen für jedes logische Segment von wenig vertrauenswürdigem Code (z. B. jede Site in Internet Explorer). Für jede Anwendungsdomäne sollten zwei Vertrauensstufen vorhanden sein:

  • Die erste Vertrauensstufe ist voll vertrauenswürdiger Plattformcode. Dazu zählen das .NET Framework und der vertrauenswürdige Hostcode, der mit dem wenig vertrauenswürdigen Code interagiert.

  • Die zweite Vertrauensstufe ist der wenig vertrauenswürdige Code selbst, der mit einer und nicht mit gemischten Vertrauenswürdigkeitsebenen ausgeführt wird.

Vertrauenswürdigkeit für Anwendungsdomänen
Abbildung 5 Vertrauenswürdigkeit für Anwendungsdomänen

Definieren der Sandbox

Eine weitere Aufgabe beim Hosten ist die Definition der Sandbox oder des Berechtigungssatzes, der wenig vertrauenswürdigen Code behandeln soll. Wie bereits erwähnt, werden von der CLR und von anderen Hosts wie z. B. ASP.NET einige Berechtigungssätze für Sandboxes definiert. Die zwei relevanten, durch die CLR definierten Berechtigungssätze sind der Internet-Berechtigungssatz und der LocalIntranet-Berechtigungssatz. Der Internet-Berechtigungssatz dient dem sicheren Ausführen von anonymem, möglicherweise gefährlichem Code. Er wurde von Microsoft zu diesem Zweck geprüft und stellt den einzigen Berechtigungssatz dar, der für ein solches Szenario ausführlich getestet wurde. Deshalb sollten Sie zum Hosten von wenig vertrauenswürdigem Code in der Regel diesen Berechtigungssatz verwenden. Der LocalIntranet-Berechtigungssatz verhindert, dass gefährlicher Code die Kontrolle über den Computer erlangt. Dabei werden jedoch einige Informationen wie Benutzernamen des aktuell angemeldeten Benutzers offen gelegt, von denen Benutzer unter Umständen nicht möchten, dass anonymer Code darüber verfügt. Er ist demnach für einigermaßen vertrauenswürdigen Code besser geeignet, beispielsweise Code im Intranet der Organisation.

Wie sieht es mit Hosts aus, die ihre eigenen Berechtigungssätze definieren, z. B. ASP.NET? Die mittlere Vertrauensstufe von ASP.NET bietet beispielsweise Sicherheit sowohl auf Grundlage von CAS als auch Windows, um Code einzuschränken. Ein Mitglied meines Teams hat für solche Szenarios einen schönen Ausdruck geprägt: Sandduning. Eine "Sanddüne" ist ein Satz eingeschränkter Berechtigungen, die für sich genommen nicht verhindern, dass gefährlicher Code ohne Autorisierung auf Computerressourcen zugreift. Stattdessen bietet dieser Berechtigungssatz in Kombination mit anderen Sicherheitsmaßnahmen und bei der Übersichtlichkeit von Code Vorteile. Er ist eine gebräuchliche Methode zur Steigerung der Zuverlässigkeit von Serverszenarios, in denen mehrere Anwendungen Computerressourcen gemeinsam nutzen und in denen Sie verhindern möchten, dass eine Anwendung mit mangelhaftem Verhalten einen Absturz des Servers hervorrufen kann.

Vorgehensweise beim Hosten

Wie werden diese Ideen in die Tat umgesetzt? Im .NET Framework 1.1 erstellen Sie eine Anwendungsdomäne und stellen sicher, dass die Beweise übergeben werden. Mithilfe dieser Beweise werden die Berechtigungen für die Anwendungsdomäne berechnet. Anschließend richten Sie für die Anwendungsdomäne eine Richtlinienebene ein, durch die Plattform und Hostcode volle Vertrauenswürdigkeit und allem anderen Code geringe Vertrauenswürdigkeit gewährt werden sollte. Danach legen Sie diese Richtlinie für die Anwendungsdomäne fest. Schließlich rufen Sie in der neuen Anwendungsdomäne den vertrauenswürdigen Hostcode auf, um ausgeführten, wenig vertrauenswürdigen Code zu starten.

Im .NET Framework 2.0 ist dieser Prozess einfacher:

  1. Erstellen Sie mit der neuen, einfachen Sandbox-API eine Anwendungsdomäne. Dadurch legen Sie die Vertrauensstufe für die Anwendungsdomäne, den Sandbox-Berechtigungssatz und die Liste mit vertrauenswürdigen Host-Assemblies in einem Schritt fest, ohne eine Richtlinienebene für die Anwendungsdomäne zu erstellen.

  2. Rufen Sie in der neuen Anwendungsdomäne vertrauenswürdigen Hostcode auf, um ausgeführten, wenig vertrauenswürdigen Code zu starten.

Ausführliche Informationen hierzu finden Sie in dieser Ausgabe im Artikel von Shawn Farkas. Shawn erklärt, wie hierbei vorzugehen ist, und er erläutert alle Methoden, dies sicher zu tun. Während das einfache Sandboxmodell für viele Szenarios ausreichend ist, können Sie mit der Klasse AppDomainManager die Erstellung von Anwendungsdomänen weiter steuern. In Shawns Artikel erfahren Sie, wie mit AppDomainManager benutzerdefiniertes Richtlinienverhalten bei Bedarf implementiert werden kann.

CAS und Frameworks

Nun möchte ich zu etwas anderem kommen und ein weiteres Entwicklerszenario erläutern, für das CAS wichtig ist: das Erstellen von Frameworks. Ein Framework ist eine Bibliothek wieder verwendbarer Klassen, die von anderen Anwendungen genutzt werden. Dabei kann es sich um eine Assembly mit wenigen Typen oder um einen großen Satz von Assemblies mit vielen Typen wie dem .NET Framework handeln. Frameworks werden normalerweise im globalen Assembly-Cache (GAC) bereitgestellt, so dass diese von mehreren Anwendungen verwendet werden können. Sie sind Plattform-Komponenten, die mit voller Vertrauenswürdigkeit ausgeführt werden, um alle Funktionen des Systems zu nutzen. Dieses Thema ist auch für Hostentwickler von Bedeutung, da diese normalerweise wenigstens ein eingeschränktes Framework erstellen müssen, mit dem der Hostcode interagiert, wenn nicht sogar ein vollständiges Framework.

Jedes Mal, wenn ein Framework-Entwickler nicht voll vertrauenswürdigem Code Funktionen bereitstellt, muss CAS berücksichtigt werden. Ein Beispiel ist das Erstellen einer Audiobibliothek. Beispielsweise kann eine benutzerdefinierte Berechtigung mit dem Namen SoundPermission definiert werden, die beim Aufrufen einer Methode zum Abspielen eines Sounds angefordert wird. Wenn die Anforderung erfolgreich ist, wird die Berechtigung bestätigt, nicht verwalteten Code und die Win32-API zum Abspielen des Sounds aufzurufen.

Ein anderes, gebräuchlicheres Szenario ist die Interaktion mit vorhandenen Systemberechtigungen mithilfe eines Frameworks. Angenommen, Sie implementieren beispielsweise eine Mathematik-Bibliothek, auf die von wenig vertrauenswürdigem Code zugegriffen werden kann. Wenn die Bibliothek nur Berechnungen vornimmt und nicht auf Systemressourcen zugreift, ist CAS größtenteils nicht zu berücksichtigen. Ein anderer Fall liegt vor, wenn bei der Initialisierung der Mathematikbibliothek zum Optimieren der Berechnungen einige Umgebungsvariablen gelesen werden. In dieser Situation ist eine Überwachung des Codes erforderlich, um sicherzustellen, dass dieser im Kontext von wenig vertrauenswürdigem Code sicher aufgerufen werden kann. Der Aufruf darf für wenig vertrauenswürdigen Code in keiner Weise transparent sein. Das heißt, dass der wenig vertrauenswürdigen Code nicht festlegt, welche Umgebungsvariablen überprüft werden, und der Code kann keine Werte der Umgebungsvariablen abrufen. Um den Erfolg dieser Vorgehensweise in einem wenig vertrauenswürdigen Kontext zu gewährleisten, müssen Umgebungsberechtigungen zum Lesen von Umgebungsvariablen bestätigt werden.

Eine Bestätigung stellt eine Erhöhung der Berechtigungsebene dar. Wenn Framework-Code eine Bestätigung ausführt, wird eine Operation ausgeführt, für die der Aufrufer normalerweise nicht die Berechtigung hat (das Framework muss jedoch bereits sowohl über diese Berechtigung als auch die Berechtigung zum Durchführen einer Bestätigung verfügen). Wann immer Framework-Code eine Bestätigung durchführt, muss dieser Code sorgfältig überwacht werden, um zu gewährleisten, dass die Bestätigung sicher ist. Im Allgemeinen müssen hierzu die übergebenen Parameter überprüft werden, um sicherzustellen, dass diese auf ihre Gültigkeit hin überprüft und kanonisiert wurden, so dass keine ungeeigneten Daten zu wenig vertrauenswürdigem Code zurückgeführt werden. Außerdem wird sichergestellt, dass wenig vertrauenswürdiger Code nicht in der Lage ist, den Status von Code mit hoher Vertrauensstufe auf ungeeignete Weise zu ändern, so dass dieser Code unbeabsichtigt zu einem späteren Zeitpunkt die Sicherheit gefährdet (bekannt als Köderangriff). Bestätigungen sind gewöhnlich leicht zu erkennen. Sie können im Quellcode nach ihnen suchen, und im Zusammenhang mit Bestätigungen sind einige FxCop-Regeln vorhanden.

Eine subtilere und aus diesem Grund potenziell gefährlichere Erhöhung der Berechtigungsstufe ist die Umsetzung einer Verknüpfungsanforderung. Verfügt eine Methode über eine Verknüpfungsanforderung, wird ihr unmittelbarer Aufrufer überprüft, wenn die Methode JIT-kompiliert (Just-In-Time) wird. Letztlich handelt es sich also um eine Anforderung auf einer einzelnen Stufe. Sie kann insofern gefährlich werden, als dass vertrauenswürdiger Code eine Verknüpfungsanforderung umsetzen kann, um anschließend diese Funktionalität wenig vertrauenswürdigem Code bereitzustellen, ohne dass die Umsetzung der Verknüpfungsanforderung erkannt wird. Vertrauenswürdiger Code könnte versuchen, Sicherheit zu gewährleisten, indem die Verarbeitung von Bestätigungen vermieden wird und alle Anforderungen einfach zu Aufrufern fließen. Bei Verknüpfungsanforderungen führt vertrauenswürdiger Code jedoch eine implizite Bestätigung durch. Für vollständige Sicherheit muss der vertrauenswürdige Code außerdem alle Verknüpfungsanforderungen in vollständige Anforderungen umwandeln. Obwohl mit einigen FxCop-Regeln nach Code gesucht werden kann, der Verknüpfungsanforderungen umsetzt, können Sie Code nicht visuell überwachen, um zu ermitteln, ob dieser Verknüpfungsanforderungen umsetzt. Dadurch ist Codeüberwachung anfälliger für Fehler.

Sicherheitstransparenter Code

Transparenz ist eine neue Funktion im .NET Framework 2.0. Sie unterstützt Framework-Entwickler beim Schreiben sichererer Bibliotheken, die wenig vertrauenswürdigem Code Funktionen bereitstellen. Sie können eine ganze Assembly oder auch nur einige Klassen oder Methoden in einer Assembly als sicherheitstransparent kennzeichnen. Durch sicherheitstransparenten Code kann eine Vertrauensstufe nicht erhöht werden. Dies hat drei Auswirkungen:

  • Sicherheitstransparenter Code kann Bestätigungen nicht durchführen.

  • Jede Verknüpfungsanforderung, die von sicherheitstransparentem Code umgesetzt wird, wird in eine vollständige Anforderung umgewandelt.

  • Jeder nicht sichere (nicht prüfbare) Code, der in sicherheitstransparentem Code ausgeführt wird, führt zu einer vollständigen Anforderung der Sicherheitsberechtigung zum Überspringen einer Überprüfung.

Diese Regeln werden bei der Ausführung von der CLR durchgesetzt. Im Wesentlichen übergibt sicherheitstransparenter Code alle vom Code aufgerufenen Sicherheitsberechtigungen an seine Aufrufer. Anforderungen fließen einfach durch ihn hindurch, und er ist nicht in der Lage, Berechtigungsstufen zu erhöhen. Wenn also eine wenig vertrauenswürdige Anwendung sicherheitstransparenten Code aufruft, der zu einer Anforderung einer hohen Vertrauensstufe führt, fließt die Anforderung zum wenig vertrauenswürdigen Code und schlägt fehl. Der sicherheitstransparente Code kann die Anforderung unter keinen Umständen aufhalten. Derselbe sicherheitstransparente Code führt zu einer erfolgreichen Anforderung, wenn dieser von voll vertrauenswürdigem Code aufgerufen wird.

Es gibt drei Attribute, die im Zusammenhang mit Transparenz verwendet werden, und die in Abbildung 6 aufgeführt sind. Wenn Sie mit Transparenz arbeiten, wird der Code in sicherheitstransparente und sicherheitskritische (das Gegenteil von sicherheitstransparent) Methoden zerlegt. Der Großteil des Codes, der Datenmanipulation und -logik behandelt, kann gewöhnlich als sicherheitstransparent gekennzeichnet werden. Der wenige Code, durch den tatsächlich Berechtigungsebenen erhöht werden, wird hingegen als kritisch gekennzeichnet. Bisher waren die Arbeitsgruppen bei Microsoft, die Transparenz verwenden, in der Lage, bis zu 80 % ihres Codes als sicherheitstransparent zu kennzeichnen. Dadurch konnten sie sich auf die Überwachung und Tests der 20 % Code konzentrieren, der sicherheitskritisch ist. Um Abwärtskompatibilität zu gewährleisten, wird in .NET Framework 2.0 und früheren Versionen von .NET Framework sämtlicher Code, der über keine Transparenzattribute verfügt, als sicherheitskritisch eingestuft. Vorläufig müssen Sie für Transparenz ein Opt-In durchführen. Es sind auch FxCop-Regeln vorhanden, mit denen Entwickler sicherstellen können, dass die Transparenzregeln beim ersten Erstellen von Code ordnungsgemäß angewendet werden, ohne dass zu einem späteren Zeitpunkt ein Laufzeitfehler debuggt werden muss.

Die Gründe für die Verwendung des Attributs SecurityTreatAsSafe sind zunächst nicht offensichtlich. Der sicherheitstransparente und der sicherheitskritische Code in einer Assembly sollten eigentlich wie zwei verschiedene Assemblies behandelt werden. Der sicherheitstransparente Code ist nicht in der Lage, private oder interne Member des sicherheitskritischen Codes zu erkennen. Darüber hinaus wird der sicherheitskritische Code im Allgemeinen nach dem Zugriff auf seine öffentliche Schnittstelle überwacht. Gewöhnlich sollte auf privaten oder internen Status außerhalb einer Assembly nicht zugegriffen werden können - es empfiehlt sich, den Status zu isolieren. Das Attribut SecurityTreatAsSafe dient also der Isolation des Status zwischen sicherheitstransparentem und sicherheitskritischem Code, während ein Überschreiben bei Bedarf immer noch möglich ist. Von sicherheitstransparentem Code kann nicht auf private oder interne Member von sicherheitskritischem Code zugegriffen werden, solange diese Member nicht als SecurityTreatAsSafe gekennzeichnet sind. Bevor das Attribut SecurityTreatAsSafe hinzugefügt wird, sollte der Autor von kritischem Code das Member überwachen, als ob dieses öffentlich bereitgestellt wird.

Verwenden von Transparenz

Die Syntax für Transparenz lässt sich anhand des Beispiels einer Mathematikbibliothek veranschaulichen. Zunächst sollte zum Durchführen eines Opt-Ins für Transparenz das Attribut SecurityCritical auf Assembly-Ebene hinzugefügt werden:

using System.Security;

// opt in to low-trust callers
[assembly: AllowPartiallyTrustedCallers]
// opt in to transparency, but some code will be critical
[assembly: SecurityCritical]

Nun sind alle Typen in der Assembly standardmäßig sicherheitstransparent. Angenommen, der Konstruktor für die Mathematikbibliothek-Klasse muss zum Lesen einer Umgebungsvariablen eine Bestätigung durchführen, während alle anderen Methoden in der Bibliothek sicherheitstransparent sein können. Eine Möglichkeit für eine entsprechende Klassendefinition ist in Abbildung 7 dargestellt.

Mithilfe von Transparenz können Sie Frameworks erstellen, in denen ein Großteil des Codes im Kontext seines Aufrufers ausgeführt wird, während der Code, durch den Berechtigungsebenen erhöht werden können, explizit gekennzeichnet wird. Dadurch können Sie sich hauptsächlich mit der Sicherheit von besonders gefährdetem Code befassen. Dies ist besonders wichtig, wenn die Codebasis eine gewisse Größe erreicht. Darüber hinaus wird das Erstellen und Warten von Code für wenig vertrauenswürdige Aufrufer vereinfacht.

Schlussbemerkung

In diesem Artikel wurden die vielen Möglichkeiten von Standardsandboxes erörtert. Entwickler, die wenig vertrauenswürdigen Code hosten oder die Plattform erweitern möchten, müssen über fortgeschrittenere Kenntnisse von CAS verfügen. .NET Framework wurden neue Funktionen hinzugefügt, die das sicherere Hosten von wenig vertrauenswürdigem Code und das Erweitern der Plattform vereinfachen. Während verwalteter Code immer mehr Verbreitung findet, wird CAS weiterentwickelt, um das Ausführen von wenig vertrauenswürdigem Code in einer Sandbox und das Erstellen einer sichereren Plattform zu erleichtern. Informationen zu weiteren Änderungen von CAS in .NET Framework 2.0 finden Sie in der Randbemerkung "What Else is New in CAS?" (in englischer Sprache). CAS wurde für .NET Framework 2.0 entwickelt, damit Entwickler diese Szenarien nutzen können, und um gesicherte Erweiterbarkeit zu ermöglichen.

Der Autor

Mike Downen ist Program Manager für Sicherheit im CLR-Team. Er befasst sich mit CAS, Kryptografieklassen und dem Sicherheitsmodell ClickOnce. Sie können unter blogs.msdn.com/CLRSecurity Mikes Weblog lesen oder ihm Fragen stellen.

Aus der Ausgabe November 2005 des MSDN Magazine.